Cover illustration

TheDaily Front

Issue No. #261005 Monday, October 5 2026 #261005 — MONDAY, OCTOBER 5, 2026
Privacy alarms, agent ambitions, and one very nervous race grid.
Monday, October 5, 2026 The Daily Front No. #261005 — Contents
30stories
7,090points
4,619comments
265kllm tokens
Assembled with 30 model calls — 183,922 tokens read, 81,240 written.

Highlights

Anthropic reported diary entry to police, woman faces felony charge

A Claude diary entry reported to police puts AI confidentiality, human review, and threat reporting under a harsh spotlight.

Denmark data breach exposes 8.8M people's personal data

Unauthorized access to Denmark’s central register exposed personal data for roughly 8.8 million people.

Beam: Reflection's 501B open-weight model

Reflection releases Beam, a 501B-parameter open-weight mixture-of-experts model aimed at coding and agents.

Opus 5.5 agents discover two room-temperature magnetic semiconductor candidates

Agents using Opus 5.5 propose two room-temperature antiferromagnetic semiconductor candidates, with experimental proof still to come.

Nobel Prize in Physiology or Medicine 2026

The 2026 medicine Nobel recognizes optogenetics, the light-controlled technique that transformed neuroscience.

From the Editor

The day’s dispatches carry a common warning: entrust more to machines, and one must ask who watches the watcher. Still, there is wonder in the laboratory and workshop—provided we remember that a promising result is not yet a settled fact.

  1. Anthropic reported diary entry to police, woman faces felony charge3
  2. Web Search API4
  3. Find the flattest route between any two points in SF4
  4. Denmark data breach exposes 8.8M people's personal data5
  5. Beam: Reflection's 501B open-weight model6
  6. Powerless F1 drivers frustrated by Bahrain F1 software glitch7
  7. OpenAI "rogue" agent activities found on Wikimedia projects8
  8. Opus 5.5 agents discover two room-temperature magnetic semiconductor candidates9
  9. Mold Linker Version 3.0.0 Release – Rewritten in Rust10
  10. Apple and a hacker's future11
  11. US closely monitoring case of lab worker who possibly died of plague in Siberia12
  12. Plain text is still one of the best technologies we have13
  13. The lamps in my house14
  14. Texas city demands $2M for public records on Flock usage15
  15. Making a GTK application in Haskell, part 116
  16. Dust: Pretraining Transformers Without Backpropagation17
  17. The future of independence is interdependence18
  18. Example.com just launched the biggest redesign in decades19
  19. Picard 3.020
  20. Linux containers in 500 lines of code (2016)21
  21. A 40ms Go garbage collector pause caused by swap22
  22. Nearly 200 people under observation after Irkutsk lab worker dies from plague23
  23. Nobel Prize in Physiology or Medicine 202624
  24. 2026 Nobel Prize in Physiology or Medicine: Deisseroth, Hegemann, Nagel24
  25. "I'm Embarrassed on Behalf of the Tech Industry"25
  26. Pixel 11 doesn't yet meet the GrapheneOS security standards and may be skipped26
  27. ChatGPT is adding real cartoonists' signatures to fake New Yorker cartoons26
  28. Germany’s RobCo hits $1B valuation26
  29. Qualcomm licenses patents on Huawei’s LogicFolding chip tech26
  30. Norway Eyes Partial Ban of Smart Glasses26
The Daily Front Page 2 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — The AI Diary and the Constable
article

Anthropic reported diary entry to police, woman faces felony charge

by emptybits·▲ 629 points·502 comments·techspot.com ↗
Another incident has taken place that illustrates the need to be careful what you tell AI.

The woman now faces a felony charge

Florida woman used Claude as a diary, then Anthropic reported an entry to police

What just happened? Another incident has taken place that illustrates the need to be careful what you tell AI. A Florida woman is facing felony charges after she used Claude as a diary and allegedly wrote that she planned to "shoot up" the Sheriff's office. After a human reviewer examined the statements, they were reported to police.

According to the arrest report, Carli Michelle Heller, of Bonita Springs, Florida, wrote on September 26 that she would attack the Sheriff's office. She later said that she uses Anthropic's chatbot like a "diary."

Claude's safety systems flagged the entry and it was escalated to a human reviewer. After deciding it was a credible threat, the reviewer reported it to law enforcement.

The company says it may share user information in limited emergencies if it believes disclosure is necessary to prevent death or serious physical injury.

Deputies identified Heller and visited her home. She was detained without incident before an LCSO intelligence detective took over the investigation.

Heller faces a charge of making a written threat of violence under Florida law. Florida Statute 836.10 makes it a second-degree felony to send, post, or transmit a written or electronic record threatening to kill or injure someone, carry out a mass shooting, or commit an act of terrorism. The communication must be made in a manner in which another person may view it.

Anthropic isn't going to be taking any chances when it comes to anything it deems a potential threat. Last month, it was reported that OpenAI and Sam Altman are being sued by British Columbia over claims that the company could have prevented a mass shooting in the Canadian province.

The shooter, eighteen-year-old former pupil Jesse Van ⁠Rootselaar, had previously been flagged by OpenAI's safety team for her conversations about gun violence, but OpenAI never alerted police because the conversations did not meet the threshold for legal referral.

In June, Florida also sued OpenAI and Altman, alleging that ChatGPT had contributed to real-world harms, including the 2025 Florida State University shooting.

The latest incident is another reminder to think before you enter something into a chatbot that could get you into trouble. It's certainly not a private diary whose contents are for your eyes only.

Reports last month revealed that human contractors reviewing Microsoft Copilot's image editor can see users' prompts, uploaded photos and AI-generated edits. Documents show that some of those assignments contain sexual, disturbing or potentially illegal material, though the reviewers are not there to flag the content – only to assess whether the output is accurate.

The Daily Front Page 3 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Search, Grounded
article

Web Search API

Web Search API is now available in beta. Web Search API lets your AI agents and applications search the Internet and ground their responses in live information, instead of guessing URLs or relying on a model's training cutoff.

At launch, you can choose between three search providers: Ceramic.ai, Exa, and Linkup. All three support Zero Data Retention for requests made through Cloudflare, and all have committed to Cloudflare's verified bot crawling standards.

Web Search API runs through AI Gateway, so search requests appear in your gateway logs and are billed to your AI Gateway credits at each provider's list API price, with no additional markup. You can also bring your own provider API key.

Call Web Search API with the REST API:

curl https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/ai/websearch/ \
  --request POST \
  --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "query": "What are some fun things to do in Salt Lake City as fall approaches?",
    "provider": "ceramic",
    "limit": 5,
    "options": { "gateway": { "id": "default" } }
  }'

Or from a Worker with the AI binding:

const response = await env.AI.websearch({
	gatewayId: "default",
	query: "What are some fun things to do in Salt Lake City as fall approaches?",
	provider: "exa",
	limit: 5,
});

const results = await response.json();

To get started, refer to How to use Web Search API.

article

Find the flattest route between any two points in SF

by ishan0102·▲ 146 points·49 comments·flattensf.com ↗

Routes are computed in your browser over 160,000 street segments, using USGS 1 m lidar elevation and the Overture / OpenStreetMap street graph. The slider runs along the whole trade-off between distance and climbing: every route that nothing else beats on both counts, from the shortest path to the flattest one worth walking (where a foot of climb costs 200 ft of walking; beyond that the routes stop being routes). Sliding right never shortens the route and never adds climbing. Climbing is cumulative gain, not the net difference between the endpoints. Stairways are allowed on foot and excluded on a bike. Faint lines show the other routes along the way. Place search is offline: street intersections, places and addresses for San Francisco are built into this page. Source, data and the full analysis.

The Daily Front Page 4 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — A Nation’s Register, Exposed
article

Denmark data breach exposes 8.8M people's personal data

by clan·▲ 471 points·330 comments·cpr.dk ↗
uvedkommende skaffet sig adgang til navne, adresser, CPR-numre mv. på ca. 8,8 millioner registrerede borgere

Det Centrale Personregister (CPR) har konstateret en alvorlig sikkerhedshændelse. Ved at misbruge en dansk virksomheds lovlige adgang til at søge oplysninger i CPR-systemet, har uvedkommende skaffet sig adgang til navne, adresser, CPR-numre mv. på ca. 8,8 millioner registrerede borgere i CPR-systemet.

Den foretagne gennemgang viser, at den uautoriserede adgang ikke omfatter navne og adresser på personer, som har valgt at lade sig registrere med navne- og adressebeskyttelse. 

CPR-administrationen har stoppet virksomhedens adgang og er sammen med specialister og myndigheder i gang med at kortlægge hændelsesforløbet. CPR-administrationen har foretaget anmeldelse til Datatilsynet, og sagen efterforskes af politiet i samarbejde med relevante myndigheder.

Det er muligt at læse mere om denne sikkerhedshændelse på Forsknings-, Uddannelses- og Digitaliseringsministeriets hjemmeside: https://ufm.dk/aktuelt/pressemeddelelser/2026/oktober/omfattende-uautoriseret-adgang-til-borgeres-cpr-oplysninger/

The Daily Front Page 5 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Open Weights, Heavy Metal
article

Beam: Reflection's 501B open-weight model

by Philpax·▲ 375 points·112 comments·reflection.ai ↗
Beam is a sparse Mixture-of-Experts model with 501 billion total parameters, 23 billion active.

We are introducing Beam, Reflection’s first open-weight model. Beam is a sparse Mixture-of-Experts model with 501 billion total parameters, 23 billion active, built for coding, reasoning, and agentic workloads.

Beam’s capabilities come from major investments in both pretraining and reinforcement learning (RL). We pretrained the model on 23.8 trillion diverse, curated, high-quality tokens from the web and proprietary licensed datasets, matching or outperforming available similar-sized open base models. In parallel, we developed the algorithms, training environments, and infrastructure needed to sustain high-compute RL at exceptional scale. Our high-compute RL run generated over 100 million rollouts on 10.5K NVIDIA GB300 GPUs over 4 weeks of training.

Together, these efforts produced competitive open-weight performance with frontier inference compute efficiency.

Beam is undergoing final red-teaming and evaluations. You can sign up here for early access to the model. We will release the weights, technical report, model card, and developer artifacts later this month.

Model Capability

We trained Beam with a particular focus on coding and agentic performance. Beam advances the Western open-weight frontier and is competitive with larger open models like GLM 5.2 and approaching Qwen 3.8-Max on coding and agentic tasks. Where frontier open models like Kimi K3 remain ahead on raw capability, Beam's advantage is efficiency at inference time.

The below figure shows Beam's performance across a range of coding, agentic, reasoning, and STEM benchmarks. NR denotes scores that have not been reported.

Beam pairs coding and agentic capabilities with highly efficient reasoning. On advanced reasoning benchmarks, it achieves scores comparable to GLM-5.2 while using 3–4× less inference compute. Efficiency gains are even more pronounced when comparing to models in the 2T+ parameter family like Qwen 3.8-Max, which require significantly more inference compute per token.

These results translate into more intelligence per token, delivering strong model capabilities at lower cost, making Beam a powerful workhorse model for enterprise coding and agentic workloads.

Figure 2: Beam demonstrates frontier-level inference efficiency, both when measured in terms of FLOPS and token count across DeepSWE, Humanity’s Last Exam (HLE), and Terminal Bench 2.1. We used data from Artificial Analysis and DataCurve, estimating generation forward-pass compute as FLOPs ≈ 2 × active parameter count × mean generated tokens per attempt, counting each multiply-add as two operations. Generated tokens include both reasoning and the final answer. For mixture-of-experts models, we used the parameters activated per token rather than the total model size. These estimates exclude prompt prefill, context-dependent attention operations, and serving overhead, so they represent an approximate compute comparison rather than measured inference cost. We use Artificial Analysis and DataCurve as sources for other model’s evals.

High-Compute Reinforcement Learning

We made high-compute reinforcement learning a central scaling axis for Beam, investing in RL science, data, and infrastructure to turn more compute into stronger capabilities. Scaling RL enables more extensive exploration of problem-solving strategies, while longer rollouts support multi-step reasoning, tool use, and adaptation to environment feedback.

To scale reinforcement learning, we deployed 10.5K NVIDIA GB300 GPUs for four weeks generating more than 100 million rollouts with a maximum context length of 256K tokens. Training and grading used approximately 1.3 billion sandboxes. To sustain a run of this magnitude, we sourced one million high-quality coding, agentic, and STEM environments. We believe this is one of the largest scale RL runs conducted by any open lab to date. Across our evaluation suite, capabilities continued to improve as we increased RL compute, with no sign of a plateau.

Figure 3: Terminal-Bench 2.1, HLE, and DeepSWE scores as a function of cumulative RL rollouts during training of Beam’s reasoning expert, accounting for 80M of the over 100M rollouts generated across the full RL campaign. For comparison, Inkling was trained on 30M rollouts and MiMo on 753K.

We trained Beam with asynchronous policy gradients. At scale, policy staleness becomes a major source of instability for these methods. Long running rollouts have tokens that are generated by multiple model checkpoints, with earlier tokens becoming increasingly stale relative to the current policy. Numerical mismatch between training and inference engines further compounds this challenge.

We developed new algorithms to maintain stable learning under these conditions while systematically reducing training–inference mismatch throughout our pipeline. These advances enable fully asynchronous RL at scale that remains stable, even when learning from interactions generated more than a day earlier.

Figure 4: Stable learning continues as staleness builds up over time. The top plot shows the oldest sample in the batch, with the bottom plot demonstrating stable numerics. Even when training Beam with one-day staleness—107 weight versions behind the current policy—the numerics remain stable.

Learning to reason efficiently

We trained Beam with a controllable length penalty that rewards successful solutions while discouraging unnecessary tokens. Early in RL, performance improved even as completion lengths fell: the model learned to solve tasks more effectively with less reasoning. Later, as Beam developed stronger agentic capabilities, completion lengths grew again, but those additional tokens supported further gains in performance. Throughout training, RL improved the tradeoff between capability and token usage.

Figure 5: DeepSWE scores during part of the RL run. Each point corresponds to a different reasoning effort. The Pareto frontier moves in two phases. First, it contracts as the policy learns to be more token efficient. Then, the higher reasoning efforts expand outwards to achieve high performance.

Users can control this tradeoff through Beam’s reasoning effort parameter: lower settings favor shorter responses, while higher settings allow longer reasoning to improve performance on demanding tasks. This gives users the flexibility to match reasoning effort to their task and compute budget.

How behavior generalizes with RL

We designed Beam’s RL training to develop reasoning and agentic capabilities that generalize beyond its training tasks. During a phase of training on reasoning, software engineering, and terminal tasks, we saw consistent gains in browsing despite the absence of browsing tasks from the RL mixture. This transfer suggests that Beam was learning broader agentic capabilities that generalize across domains. When given web access, it organically learned to search for and query other large language models, and to use OCR APIs to read documents.

The demos below showcase Beam applying these capabilities across research, application development, gameplay, and machine learning workflows. The examples range from building a live NYC subway dashboard using public data to creating interactive applications and preparing model fine-tuning notebooks. Although Beam is text-only, it can work with information from other modalities when represented as text. In another out of distribution domain, Beam also created a fine-tuning notebook for the latest and smallest Gemma-4 model on a Text2SQL task.

Together, these demos illustrate the breadth of tasks Beam can tackle by combining reasoning, coding, and tool use. Each example includes the initial request and resulting output, along with relevant setup and user iterations.

Astronaut Free-Fall Game: Beam was prompted to create a 3D game in p5.js where an astronaut is free falling towards earth. The character must dodge asteroids that are coming towards it or destroy them with “beams.” Beam is not multimodal, but it is able to reason about how the game visuals should look like in text.

Land/Water Generalization Experiment: We recreated the viral X puzzle by asking Beam to create a fixed 180×90 grid for longitudes -179° to 179° and latitudes -89° to 89°, with 16,200 points. Beam gets 95.5% coverage right, putting us between Opus 5 (92.5%) and Fable 5 (97.8%), which shows how well it generalizes to novel new tasks.

NYC Subway Live Map: We asked Beam to create a live updating subway map for the NYC subway using the publicly available NYC MTA data. The model searches for documentation, checks authentication requirements, finds subway and map geometries, and gets creative moving the trains in between stations. Beam builds the right frontend and backend and ensures the server keeps running for live updates.

Model Fine-tuning Notebook: We plugged Beam into OpenCode, asked it to look at Unsloth, and create a fine-tuning notebook for the latest and smallest Gemma-4 model on a Text2SQL task – an out of distribution domain for Beam. The model successfully researches the model cards, Unsloth documentation, and available READMEs, and implements the fine-tuning logic and surrounding machinery. As a result, Beam is able to successfully finetune Gemma, increasing Gemma’s accuracy on its heldout test set by 66.5%.

Scaling reinforcement learning environments

Frontier-scale reinforcement learning requires a large volume of difficult, high-quality tasks. We built a pool of nearly one million environments, primarily through synthetic data pipelines, supplemented by proprietary vendor data and open-source sources.

We relied heavily on an iterative curation process. First, we synthesized or sourced environments across a broad set of domains including software engineering, terminal use, competitive coding, STEM, web search, tool use, and general knowledge work. Second, we heavily filtered tasks for difficulty (ensuring they were neither consistently solvable, nor impossible for the model) and quality (e.g., not underspecified, misleading, guessable, hackable, or otherwise broken or noisy). Third, we tested the tasks through RL, which allowed us to identify further quality or difficulty issues and inform the next iteration of sourcing and filtering.

Throughout Beam’s development, we found that compromises in data quality led to capability plateaus and other training issues. Systematic improvements to task quality were essential to sustaining capability gains throughout the run, which ended with no sign of saturation.

Frontier RL infrastructure

High-compute agentic RL requires generating rollouts, executing tools, evaluating outcomes, and updating the model at scale. We built an asynchronous platform that lets these processes run independently while coordinating the flow of experience and model updates.

During Beam’s training, we sustained an average of 110K concurrent rollouts. Seven capabilities made this practical:

Fully asynchronous execution: Agents generate rollouts while the trainer learns and publishes new model versions. Each token is tagged with the version that produced it, allowing the training algorithm to account for policy staleness as completed rollouts flow into training.

Flexible compute allocation: We adjusted the balance between inference and training as the workload evolved, operating at inference-to-training GPU ratios from 3.9:1 to 5.4:1. We also resized the trainer across five GPU mesh configurations within the same training lineage without losing training state.

Fast model updates: New weights reached the inference fleet in a median of approximately 12 seconds. Hierarchical distribution transfers weights across racks over RoCE, then shares them locally over NVLink. Compared with every replica pulling weights directly, this reduced cross-rack traffic by 75% and made fleet-wide adoption of new weights 2.2× faster.

Resilience to inference failures: During the run, 71 inference incidents were handled without terminating the training job. Inference capacity recovered in a median of eight minutes, with lost capacity accounting for just 0.02% of elapsed serving GPU-minutes.

Environments at scale: We supported up to 170K concurrent sandboxes during the run. Across the platform, we processed more than one billion sandbox creation requests, spanning over 20 clusters, two clouds, and four regions. 90% of new sandboxes were ready in under 10 seconds.

Efficient Trainer Packing: Dynamic packing kept training batches 99.99% full on average, holding per-GPU trainer throughput within 1.5% as mean rollout length grew almost 70%.

Observability and reward integrity: Per-token records enabled numerical consistency checks between training and inference at every step. Independent judges re-screened passing solutions for verifier exploits, while replayable records made rewards and their use in training inspectable.

Together, these capabilities enabled us to train on longer interactions and more demanding environments while maintaining throughput, recovering from failures, and checking the integrity of the learning process.

Pretraining a Foundation for Reasoning

Reinforcement learning builds on top of a robust base model. To facilitate reasoning, we ensured Beam’s foundation had rich knowledge in coding domains, innate agentic capabilities that could be amplified, and stable MoE optimization dynamics.

While developing Beam, we pretrained a series of iteratively bigger models to establish and verify our scaling recipe. Making their performance predictable required carefully designing model tiers, curating diverse in-house code and web validation sets, and aggressively decontaminating all training data against them. The scaling held; the final Beam Base matches its predicted performance, and also matches or outperforms accessible similar-sized open-source base models.

Figure 6: Beam’s pretraining recipe scales predictably across four orders of magnitude in compute. It achieves Pareto-optimal loss – compute performance on decontaminated code and web validation data among all comparable open base models.

Stable and balanced MoE optimization

The Beam architecture and optimization recipe emphasizes a numerically healthy foundation for sustained downstream RL. It combines interleaved local and global attention, fine-grained routed experts, a controlled residual stream, and multiple forms of load balancing to ensure stable, balanced expert utilization and healthy signal propagation through residuals.

For expert utilization, we built on auxiliary-loss-free load balancing (DeepSeek-AI et al., 2024), introducing cosine decay of expert-bias updates to reduce routing perturbations later in training. Sequence-level balancing further encourages balanced expert utilization on data outside the pretraining distribution, preparing the model for the changing distribution of downstream RL. As a result, the final pretrained base has almost-perfect uniform utilization, ensuring all experts can be used for learned reasoning.

Figure 7: Beam’s expert utilization is near-uniform. The busiest expert’s load, averaged across MoE layers, reaches just 1.04× at pretraining completion.

For the residual stream, we developed a depth-based scaling approach that counteracts activation growth as sublayer outputs accumulate, helping keep residual norms stable as model depth increases. Combined with SandwichNorm, elementwise attention gating, and FP32 residual accumulation – which reduces rounding error when adding small updates to the stream – this recipe controls activation growth and outliers, thereby ensuring healthy signal propagation throughout all layers of Beam. This stability persists throughout pretraining, reinforcement learning, and alignment.

Figure 8: Residual stream RMS remains bounded throughout pretraining across all 52 layers of Beam, with smooth, depth-dependent trajectories and no sustained activation growth.

Quality-centric data curation

Beam was pretrained on 23.8 trillion diverse high-quality tokens from the web, public sources, and proprietary licensed datasets. Our data pipeline was designed to give Beam a foundation for downstream agentic coding: source code, technical explanations, and mathematical and scientific knowledge, preserved through every stage of curation. We train on almost all publicly accessible and unrestrictively-licensed code and code documentation on the web.

We trained our own quality classifiers for web, code, and STEM content, divided data into fine-grained quality tiers, and weighed training toward stronger material. After extensive scientific iteration, we optimized both precision and recall of data curation significantly beyond conventional web filters used in state-of-the-art OSS data frameworks. On one hand, about 95% of raw Internet tokens are eliminated through parsing, deduplication, and curation. On the other hand, we found that conventional techniques would have missed roughly 1.8 trillion high-quality tokens we retain, including 87% of our curated web-code tokens.

Code modeling requires its own curation for the highest performance. For each language, we applied individually tuned filters, removed low-quality autogenerated and unlearnable content, and trained classifiers to identify corrupted content or code that may hurt training stability. Overrepresented languages and file types are rebalanced to further broaden exposure.

We also developed a high-throughput pipeline for processing PDF artifacts, to ensure the base Beam has knowledge across a wide range of STEM topics. It integrates a vision-language OCR model with in-house quality classifiers and artifact detectors that catch malformed reconstructions, distributed across thousands of GPUs to process petabytes of technical data.

We repeated code and technical content multiple times to increase the model’s exposure over the course of its training horizon. This required careful attention to fuzzy deduplication, packing algorithms, and the science of overtraining, to ensure every repeated data source helps rather than hurts generalization.

Frontier-grade pretraining infrastructure

Beam was pretrained end-to-end in under four weeks on a cluster of 6,144 NVIDIA GB300 NVL72 GPUs. To achieve the reliability, performance, and development velocity required to train Beam at scale, we built nearly the entire infrastructure stack in-house. This included a novel topology-aware, Kubernetes-based scheduler across our clusters; an internal node lifecycle system with continuous health monitoring and alerts; and a silent data corruption (SDC) detection system capable of semi-autonomous rewinds and restarts. Together, these systems gave us the performance and operational control required to train our own frontier model efficiently and with greater stability.

As a result of extensive investments in the training recipe stability, infrastructure, and data quality, the overall pretraining run finished with an extremely smooth trajectory. We executed nine semi-automatic rewinds throughout, attributed either to non-deterministic gradient norm spikes or to suspected SDCs. In addition, the run’s goodput (the share of wall-clock time spent on training steps retained in the final model) reached 92.3% towards the end thanks to improvements in checkpointing, fault detection, and node health management.

Figure 9: Beam training loss over the course of its pretraining run. We observed no instabilities or large irrecoverable spikes.

Building a strong prior for RL in Midtraining

Our midtraining stage was designed specifically as a foundation for high-compute RL, developing the knowledge, reasoning, and tool-use capabilities that allow Beam to learn from more demanding tasks.

We built multi-stage data curation pipelines that capture the structure and complexity of real-world tasks while expanding coverage of capabilities that are difficult to learn from raw data alone. Starting from carefully selected real-world examples, these pipelines transform, combine, and extend material into training data designed to teach specific capabilities. This includes long, reasoning-rich documents that expose the model to extended chains of logic.

Midtraining also extends Beam’s effective context length to 1M tokens. We combine structured code repositories, long-horizon tasks, and high-quality long-form documents to teach the model to identify, retain, and connect relevant information across long sequences.

Together, these capabilities give RL a stronger starting point, enabling Beam to explore more complex solutions, work through longer interactions, and learn from tasks that would otherwise be out of reach.

Safety and Alignment

Our safety and alignment work involved training a second model from our pretrained checkpoint using a separate SFT and RL pipeline on data specifically targeting the principles by which the model should abide. We merged the capabilities of the two teachers – a large-scale RL teacher and a dedicated safety and alignment teacher – via multi-teacher on-policy distillation (MOPD).

We organized Beam's safety and alignment principles into three tiers:

(1) Rules that Beam should not break: following our safety policies and maintaining its identity as an AI agent.

(2) Qualities that Beam should consistently satisfy, such as: using the context it is given, making accurate claims, acknowledging uncertainty, and transparently following the user’s request.

(3) The default style for how Beam should interact: direct, thorough, efficient, and proactive in anticipating what the user may need next.

Figure 10: Alignment & safety RL predictably shapes Beam’s behavior across non-verifiable domains. From the pre-RL checkpoint, we are able to accurately forecast (dashed line) improvement in training reward (dots).

We designed the RL environments in the alignment stage to incentivize Beam’s adherence to these principles. Many of these environments involved non-verifiable rewards judged by a generative reward model, yet we were able to use them to predictably shape the model’s behavior. Forecasting how rewards would affect different behaviors before running RL, we were able to predict RL gains better than the Best-of-N ceiling alone (r = 0.79 compared to r=0.46 with BoN ceiling). This allowed us to iterate on rubrics and reward design, squash behaviors like hallucinations and excessive formatting, and improve Beam’s overall interaction quality.

Our safety training used deliberative alignment (Guan et al., 2024) techniques to incorporate our safety policy directly into the model's reasoning. The dataset was built adversarially and iteratively: in each round, we trained a model, generated prompts that elicited harmful or over-refusing behavior from it, and folded the successful attacks back into SFT mixture for the next round. For safety RL, we similarly sourced single-turn, multi-turn, jailbreak, and agentic scenarios in which a simulated adversary pressures a tool-using model to take unsafe actions, to simultaneously reduce over-refusals and harmful compliance.

We will publish the results of our safety evaluations in our model technical report and will open-source safety evaluations we developed and used internally to create a shared, inspectable standard that the open ecosystem can test against and contribute to.

The Path Ahead

This preview shows what Beam can do today. We are making this early version of Beam available to a select group of users; you can sign up for the waitlist here.

We want Beam to be widely accessible and easy to build on. This month, we will release the weights under an Apache 2.0 license, along with documentation and the full stack for running, evaluating, and fine-tuning the model. We will be launching Beam with an ecosystem of distribution partners, as well as integration with a broad range of open source libraries and harnesses, so developers can use Beam across existing open-source workflows.

Beam is the first model in a series, and the first demonstration of the open intelligence our team is committed to building. We are already training what comes next, with the goal of bringing the open frontier closer to the frontier of intelligence with every release.

The Daily Front Page 6 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — The Grid Goes Dark
article

Powerless F1 drivers frustrated by Bahrain F1 software glitch

by llm_nerd·▲ 283 points·248 comments·motorsport.com ↗
"Horrible, totally unacceptable"

Formula 1 drivers have weighed in on Bahrain GP's unprecedented software glitch that left them powerless on the formation lap

Max Verstappen, Red Bull Racing

Max Verstappen, Red Bull Racing

Photo by: Joe Portlock / Getty Images

Leading F1 drivers are despairing at power unit software glitches that derailed the start of the Bahrain GP in Malaysia, with Lando Norris calling the electronic glitches "horrible" and further proof that F1 should move away from hybrids.

The start at a wet Sepang circuit was aborted after a large number of cars suffered crippling software issues. With the event being the first wet weather race contested by the 2026 generation of cars, a bug in the software when drivers were driving at very low speeds, triggered by the power unit controller's wet weather mode, left drivers stuck into idle mode at various points of the two planned formation laps.

With several cars stuck into that idle loop, the FIA had to rapidly code and deliver a software patch for all 11 teams to install during the following red flag stoppage, lifting the usual wet weather power reduction in the affected zones. It took a 50-minute delay for the race to start, which was a major blemish for F1 ahead of what was otherwise an entertaining, mixed-weather race.

With drivers already harbouring misgivings on F1 2026's battery-dominated racing and the overbearing electronics that are in charge, the incident did little to further endear them to the current formula.

"It's just horrible. I don't know, it just proves that we shouldn't have any of that stuff, the electronic side," Norris said, one of the few Mercedes-powered drivers to suffer the glitch.

"I've never seen an F1 race delayed by a bug. That was a new one," Piastri said mockingly. "I got stuck for about a second. When the turbo doesn't work on these things, you might as well push the car instead of using an engine. It was quite bizarre. It wasn't a great look, but I think it would be unfair to point the finger before there's an explanation."

Lando Norris, McLaren

Lando Norris, McLaren

Photo by: Andy Hone/ LAT Images via Getty Images

Cadillac's Sergio Perez, who drove one of several Ferrari-powered cars that were affected, was less kind. "It felt like you were in a rental kart and you ran out of time," the Mexican explained. "You were putting your foot down and accelerating and nothing was coming.

"I'm sure we will learn from it as a sport. But what happened today is totally unacceptable for the sport."

Haas driver Oliver Bearman said it was "scary" for his throttle pedal being cut off by something beyond his control. "I've never seen anything like that. I was shocked," he said. "I didn't even know that the FIA could control our throttle pedal. That was quite scary, actually. My throttle pedal stopped working, but it looks like everybody stopped working as well. The engine was just idling."

Aston Martin's Fernando Alonso said there was now "too much technology" involved in the series and felt "the spectators don’t really appreciate it" either. Meanwhile, race winner Max Verstappen, whose slow getaway helped trigger the bug, likened the formation lap chaos to the Lego go-kart race in Silverstone.

"That’s the problem that we have," the Dutchman said. "These engines are so complicated and a lot of software is implemented. I triggered it first and then I looked in my mirror and I was like: 'Wait, are they waiting for me or what’s going on...?'

"Then we did a lap and then I saw eight other cars crawling still. What can you say? I mean, that’s not what you want for the sport, right?"

The Daily Front Page 7 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Agents at the Wiki Gates
article

OpenAI "rogue" agent activities found on Wikimedia projects

by brokensegue·▲ 266 points·180 comments·diff.wikimedia.org ↗
clusters of so-called “rogue” AI agents attempted to break into websites and online services

Recently, multiple organisations have disclosed how clusters of so-called “rogue” AI agents attempted to break into websites and online services, sometimes successfully. Agents from OpenAI’s environment, in particular, are known to have used other public wikis (collaboratively edited websites not owned by us) to communicate and coordinate with each other.

These types of successful intrusions can expose sensitive data or disrupt website services that users rely on, while clusters of agents can attempt attacks at a scale that is difficult for defenders to manage. They affect people behind the websites who may not understand the nature of the attack, or have the tools to effectively fight back. For a site like Wikipedia, agents might find and use security vulnerabilities or make misleading edits at scale. Wikipedia’s volunteer editors and the Wikimedia Foundation’s security teams have to detect and undo that activity.

The Wikimedia Foundation conducted its own investigation to see whether Wikimedia websites had been similarly affected by AI agents, focusing on those operated by OpenAI. We can confirm that we have discovered some activity by these “rogue” OpenAI agents on Wikimedia platforms. The unauthorized bot activities included edits to our wikis, some unsuccessful attempts to exploit a public note-taking tool we host, and heavy traffic, which are described more below.

We did not find any evidence that our systems were used for coordination among agents, nor did we find any evidence of our systems or data being compromised. However, we are concerned about what could have occurred here, the difficulty and effort involved in investigating and attributing this activity, and the growing risks of agentic AI activity on our platforms in general. The open web is a public good. We should not allow this behavior to become the “new normal” for the people or organizations that maintain it.

In summary, we saw:

  • Wiki editing: We’ve identified edits to Wikimedia wikis that we believe are from AI agents operated by OpenAI. These edits were not published to pages with visibility to general readers; almost all of them were testing edits in “sandbox” areas of the wiki. It also included a few edits to the configuration for a citation tool, which we believe were potentially malicious edits that were intended to misuse this tool as a proxy for fetching data from remote services. While Wikipedia policies allow bots to edit when they are disclosed and approved by the community, none of those approvals were sought in these incidents.
  • Etherpad probing and use: Agents we believe to be operated by OpenAI made some unsuccessful attempts to compromise our public Etherpad, a note-taking tool we host as a community service. Agents unsuccessfully tried to use it to fetch data from other websites as a proxy. Other agents also likely operated by OpenAI took notes about their tasks, though this did not appear to turn into coordination.
  • Excessive data downloading: Agents we believe to be operated by OpenAI made millions of automated requests to our public APIs to access the knowledge on Wikimedia projects, crawled millions of pages (mainly from our projects Wikidata and Wikimedia Commons), and made hundreds of thousands of data queries to the Wikidata Query Service (WQDS). This traffic may have contributed to a partial outage on WQDS in May.

As a non-profit technology host of some of the largest and most widely used open knowledge platforms in the world, we are deeply concerned about the impact of “rogue” AI agents on platforms like ours, which are built by volunteers from around the world and rely on the promise of the open internet. Incidents like this one, and the many others that have been (and are still being) uncovered, illustrate how AI agents can drain resources and crash servers, as well as attempt to compromise trustworthy information.

Over the past 25 years, Wikipedia has grown into one of the most popular and trusted websites in the world, with more than 67 million articles across over 300 languages, and up to 15 billion page views per month. Through an open, transparent, and collaborative process, volunteers work to ensure that knowledge remains neutral, reliable, and accessible to everyone. Wikipedia is one of the highest-quality datasets used in training Large Language Models (LLMs), and its knowledge forms the backbone of information on the internet, powering AI chatbots, search engines, voice assistants, and more.

Wikipedia was designed for humans – and agentic behavior clearly poses challenges that no one has solutions for. Because of our unique and successful knowledge creation model, Wikimedia’s volunteers are the ones who come in first contact with, and clean up the mess left behind by AI agents. Rising bot traffic and agentic activity is showing a real impact on the Wikimedia projects and the infrastructure that makes it available for millions of users globally. In 2025, the Foundation reported that its bandwidth usage had increased by 50% due to the surge of bot activity on its websites since 2024. At the same time, 65% of the most resource-consuming traffic on its projects was coming from bots.

This intense pressure on our infrastructure not only adds costs for servers and humans, but if left unaddressed, can block human visitors by overloading systems and causing outages. We are already paying for costs that come with the increased activity.

Wikimedia’s volunteers have stayed resilient so far in tackling emerging challenges on our platforms, but we also want to say: it doesn’t need to be this way.

While OpenAI admits to agents behaving “unpredictably”, they must also acknowledge their responsibility to monitor and prevent these risks. AI companies are not doing enough to secure their systems and protect the public from the harm they cause. That burden is falling onto everyone else, including smaller organizations. At a minimum, their systems should operate in a way that non-profit website owners like us can easily identify, and choose how they interact with our services.

The web enables so much: to connect with friends and family, to register for school, to plan a trip across town, to buy groceries, and to learn about the world from Wikipedia. Bots and agents are part of the future of the web, and the companies who unleash and profit from them must directly help avoid and repair damage they can do. 

Our collective priority should be the health of the overall web ecosystem so that it continues to benefit all people – not just a handful of billionaires. Wikimedia plays a critical role in stewarding the knowledge commons, but we cannot do it alone. We invite everyone who is building the future of the web to join us in protecting the open, shared resources that make that future possible.

The Daily Front Page 8 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Magnetism by Agent
article

Opus 5.5 agents discover two room-temperature magnetic semiconductor candidates

by outlier99·▲ 263 points·180 comments·vals.ai ↗
We’re all used to two types of magnet.

We’re all used to two types of magnet. The common one, the fridge magnet, is ferromagnetic — its atomic magnets all point the same way (up or down), adding their magnetic effects. The less well known one, the antiferromagnet (AF), has neighbouring atomic magnets that point opposite ways and exactly cancel out magnetically.

For a long time, there’s been an intense drive in computer memory research to create materials in between these two extremes. For this purpose, it helps to have a clear picture of what these extremes mean.

Today, I’ll share what we found. A team of AI agents and I designed one candidate magnet and found another, first made in 1999, that our calculations predict has the properties we were after.

But before diving into the details, let me first lay out a magnet primer that takes all of 90 seconds, assuming you are not an undergraduate in physics or chemistry.

A 90 second primer in magnets

Spin

Each electron has a quantum mechanical property called ‘spin’, which is responsible for its magnetic moment. We can model the spin direction for each electron as either pointing up or down.

Spintronics

We use spin for storage. A magnetised material stores information based on the spin up/spin down orientation of its electrons, in the same way classical magnets store information based on pointing up/down. The most prominent example of spintronics is the hard drive read head, the device that reads the magnetic bits on the disk. MRAM is another type of spintronics that uses the same principle to store binary information in a non-volatile way.

In the world of spintronics, we want to sort electrons by their spin orientation so we can read/store their information. Ferromagnets do this naturally: the electrons that carry current are mostly of one spin, up or down. Ordinary antiferromagnets, however, cannot distinguish up/down electrons.

This leads us into the next section.

Three kinds of magnets

Ferro

Ferromagnetic materials are characterised by having a macroscopic magnetic field, or a field that leaks out from the surface. This is why a fridge magnet sticks to your refrigerator door.

The problem, however, is that the magnetic field interferes with nearby materials and is difficult to control for storage purposes. In addition, switching magnets back and forth is relatively slow and consumes a lot of power.

Another feature of ferromagnetic materials is that the spins are sorted (by up/down orientation) according to energy level. We can see this when looking at the energy spectrum of the electrons: near the edges of the spectrum, the electrons all have the same spin.

Antiferro

If we take the above and flip the logic, meaning, the spins are unsorted, we end up with an ordinary antiferromagnetic material.

Here the electrons of the same energy level will instead have mixed spins. This leads us to two properties of interest:

  • Because spins are not sorted according to energy level, it is hard to read/store information using spintronics techniques.
  • However, the lack of macroscopic magnetic field allows us to pack these materials closer together, enabling higher performance for storage devices. In terms of speed, AF materials are also about a thousand times faster to switch.

The only problem is, if the spins are mixed at each energy level, how would we ever sort them by energy? How do we get a way to read/store information using spintronics with this lack of sorting?

Luttinger compensated

This brings us to a third type, Luttinger compensated (LC).

LC materials are antiferromagnets where the spin-up atoms and spin-down atoms have the same magnitude of magnetism, making the net spin moment zero (i.e. they cancel out). However, unlike in ordinary antiferromagnets, the up and down atoms sit in inequivalent environments: they can be different elements (e.g. one element points up and another points down), or the same element in two different kinds of site. The name comes from Luttinger’s theorem: in an insulator, the net spin moment of each repeating unit of the crystal must be a whole number, so once it is zero it stays locked at zero. Strictly, that holds for a perfect crystal near absolute zero; smaller effects such as spin–orbit coupling, and heat, can leave a slight imbalance.

Since the up and down atoms are not equivalent, up/down spins can now be separated (sorted) by energy, just like in ferro materials.

Let’s take the previous sections and look at how spin is distributed across the energy landscape for ferro, antiferro and LC magnets.

Three kinds of magnet: a ferromagnet, an antiferromagnet and a Luttinger-compensated magnet, with their net magnetism and how their electron levels are sorted by spin

What matters for storage is the “spin window”: the slice of energy at the edge of the band gap where every available electron state has the same spin. The larger this window compared with the thermal jiggling at room temperature (about 26 meV), the better the electrons stay sorted.

This means we’d love to have a semiconductor with a band gap, without losing the ability to separate spins by their energy levels, and with zero net magnetism.

What a spin window is

This is where our AI agents (and me) enter the scene. Let’s dive into how these agents found two promising materials for next generation computer memory.

The agents ran quantum-mechanical simulations of each crystal with the standard method for this, density functional theory, at two levels of approximation: a faster one (PBE+U) and a slower, usually more accurate one (HSE06). The band gaps and spin windows below come from the more accurate one.

Candidate 1: Designed a Luttinger Compensated Magnet, YBaMnFeO₅

First, let’s see what our AI agents designed:

  • A new compound made of only 5 elements (yttrium, barium, Mn, Fe, O). As far as we could find, it has never been made, nor proposed as this kind of magnet
  • The compound was predicted to be a semiconductor
  • This Luttinger-compensated magnet is predicted to have a 2.35 eV band gap, where spin sorting occurs at both sides of the band gap: a window of 1.0 eV for holes and 1.4 eV for electrons. Note that thermal agitation at room temperature only causes around 26 meV of fluctuation
  • Finally, our agent predicted the material to retain magnetism up to an elevated temperature: about 420 K in the raw simulation, or about 490 K after calibrating the simulation against a known magnet

While this seems like a pretty promising candidate, the design needs the Mn and Fe atoms to sit in a perfect checkerboard. When our agents simulated how the atoms arrange themselves at different temperatures, that checkerboard fell apart into a random mix at around 950 K. Making this kind of oxide takes about 900–1300 °C, and at lower temperatures the atoms barely move, so standard synthesis would likely give a scrambled crystal.

Why the ordered form of YBaMnFeO5 may be hard to reach

A scrambled crystal loses the spin sorting, so this design may be hard to make in its useful form.

Candidate 2: Identified a Luttinger Compensated Magnet in KV[Cr(CN)₆] from 1999

Shortly after, my agent found this interesting material, previously reported only in 1999, that matches many of the requirements above. Its zero net magnetism is not new: the chemists who made it designed the two metals’ magnetism to cancel. Even its spin sorting was already on paper. A 2008 study using hybrid functionals like ours plotted its electron states spin by spin, and both band edges in that plot carry the same spin. But that study was about magnetic coupling under pressure and never remarked on it. As far as we found, nobody had pointed out that this makes KV[Cr(CN)₆] a Luttinger-compensated semiconductor, put numbers on its spin-sorted windows, or tested how robust they are. It had been hiding in plain sight.

KV[Cr(CN)₆] belongs to the same family as Prussian blue, the 300-year-old pigment.

Our agent identified it as a Luttinger-compensated material:

  • It predicts the material will have a band gap of about 2.1 eV, with both band edges sorted into the same spin: windows of 2.6 eV for holes and 1.6 eV for electrons.
  • The 1999 sample stayed magnetically ordered up to 376 K (103 °C), above room temperature, as measured by the chemists who made it (365 K after the sample had been heated).
  • And most importantly, its structure locks each metal into its own site: chromium bonds to the carbon end of each cyanide and vanadium to the nitrogen end, which is exactly what YBaMnFeO₅ lacked.

These predictions are for a perfect, dry crystal. The only sample so far, from 1999, is a powder with water in its pores, and it showed a small leftover magnetic moment (0.125 Bohr magnetons per formula unit, where the perfect crystal would have zero). Our two simulation methods disagree on how much the water weakens the effect: the more accurate one (HSE06) says the spin sorting survives, while the faster one (PBE+U) says the hole window shrinks by more than half. Neither the band gap nor the spin sorting has been measured yet.

The bottom line

We identified a material that combines properties of the two familiar kinds of magnet and could be useful in spintronic devices. We believe the two materials discussed in this article are promising examples of a class of materials that have both antiferromagnetic and ferromagnetic properties.

The key features for both materials: in our calculations for perfect crystals they have zero net spin moment, yet they are semiconductors whose electrons are sorted by spin over windows far larger than the thermal jiggling at room temperature. With little stray magnetic field, they shouldn’t disturb their neighbours much.

Here is the score of our two materials:

  • YBaMnFeO₅: designed candidate; may be hard to make.
  • KV[Cr(CN)₆]: first made in 1999. Near-zero net magnetic moment in the 1999 sample (zero predicted for a perfect crystal), magnetic up to 376 K.

This suggests that materials for the next step in spintronics may already exist, waiting to be recognized. A 2025 study that predicted two other Luttinger-compensated semiconductors found that both lose their magnetic order below room temperature, and named a room-temperature one as the open goal. KV[Cr(CN)₆] has already been made, and its 1999 sample stayed ordered up to 376 K. Identifying room-temperature Luttinger-compensated semiconductors is a step toward practical spin-based technologies, particularly if their magnetic properties can be controlled through chemistry. The next step is to make KV[Cr(CN)₆] again and measure its spin sorting directly.


In the spirit of transparency, I invite the reader to go through all the computations that produced the above predictions, including the calculations behind the candidate designs. The input files, raw outputs and analysis code behind the numbers in this post, along with a one-command checker, independent re-runs and a list of known caveats, have been shared on GitHub in a public repository I created to document my research journey: github.com/spicylemonade/compensated-magnet-ledger.

The Daily Front Page 9 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — The Linker, Reforged
repository

Mold Linker Version 3.0.0 Release – Rewritten in Rust

by roflcopter69·▲ 234 points·167 comments·github.com ↗
★ 17,442⑂ 571 forks Rust

mold 🦠: A Modern Linker in Rust 🦀

mold 3.0.0 is a new major release of the high-speed linker. As we announced in the 2.42.1 release notes, we have rewritten mold from C++ to Rust, and this is the first release of the Rust version. 2.42.1 is the last release of the C++ version. The goal of mold 3.x is to close the remaining compatibility gaps with GNU ld, particularly in linker script support, and to pave the way for mold to be adopted as the default linker in Linux distributions.

mold 3.0 is meant to be a drop-in replacement for 2.42.1. It accepts the same command-line options, supports the same target architectures, and produces the same output except for the bug fixes listed below. Linking performance remains on par with 2.42.1. We verified compatibility by running the test suite on every supported target, comparing linker output across a broad range of real-world workloads and option combinations, and building all Gentoo packages. We found no regressions.

The move to Rust also makes mold safer with corrupted input files. The C++ version could read memory out of bounds on such input and crash with a segmentation fault. In mold 3.0, those reads are bounds-checked, so mold stops with a panic at the faulty access instead.

If you build mold yourself, note that the build system has changed. See "Build Changes" below.

Build Changes

  • mold is now built with Cargo instead of CMake. It requires Rust 1.95 or later and a C compiler. Run cargo build --release to build mold and ./install-mold.sh to install it; the install script accepts PREFIX and DESTDIR. The CMake options have been removed.
  • If you install mold's libraries into a directory other than $PREFIX/lib, such as /usr/lib64, set the MOLD_LIBDIR environment variable to that directory both when building and when installing mold, so that mold -run can find mold-wrapper.so.
  • mold no longer depends on oneTBB. It statically links mimalloc 3.5.3 as before; build with --features system-allocator to use the system's malloc instead. mold links the system's zlib if available and includes zstd and BLAKE3; set ZSTD_SYS_USE_PKG_CONFIG=1 to link the system's zstd. (56ee0f8)
  • The MOLD_TARGETS CMake variable has been replaced with Cargo features. As before, distributions should build mold for all targets.
  • The test suite now runs with cargo test instead of ctest. install-build-deps.sh has been replaced with install-test-deps.sh, which you need only to run the tests.

Bug Fixes and Compatibility Improvements

  • Fixed a crash when creating a statically-linked executable with a version script or --default-symver. (f10b0c4)
  • Fixed a crash or a corrupted output when the output file is also an input file, as in mold -r -o foo.o foo.o bar.o. (d2b88ab)
  • --gc-sections no longer removes the functions given by --init and --fini. (c9e4cc4)
  • Common symbols of the same name with different sizes now get the largest size and the strictest alignment, as in GNU ld and lld. (d5781d5)
  • --icf=safe no longer folds functions exported from a shared library, and --icf=all no longer crashes with --emit-relocs. (ceab12c, 3dcd1df)
  • A versioned reference such as foo@VER in a shared library no longer pulls in an archive member that defines an unversioned foo. (#1657) (44bfa2a)
  • Fixed several cases of nondeterministic output, in --dependency-file, --repro, -r with many COMDAT groups of the same name, and some dynamic relocations. (5164561, 6d33903, 51e23d4, 696ed71)
  • Fixed several -r bugs: C++ exceptions broke in code from the second and later input files; -x, -X and -s removed symbols that relocations referred to; --gc-sections dropped data that relocations referred to; sh_link of SHF_LINK_ORDER sections such as .ARM.exidx was not set; and mold crashed with --strip-debug and DWARF type units. (0e41bb9, 3717460, b2c3d1d, 9aacb62, a247ca2, e41ed90)
  • GOT-relative relocations such as R_X86_64_GOTOFF64, and R_ARM_REL32, against symbols defined in shared libraries silently got wrong addresses. They are now handled correctly or reported as errors. (#1668) (659780e, 7fe68bf)
  • Errors for PC-relative relocations that can't be used in position-independent output now explain the cause and how to fix it. (39e6a01, 17b7b85)
  • The following now cause errors instead of a broken output or a crash: --defsym aliasing a symbol defined in a shared library, an undefined non-weak hidden symbol in a shared library or with --unresolved-symbols=ignore-all, a --defsym value that doesn't fit in 64 bits, an allocated section that is also compressed, and --strip-all with --emit-relocs. (56b862b, b3566fa, e3a89f2, a980054, 8233a75)
  • --noinhibit-exec no longer crashes on references to symbols in discarded COMDAT groups. (8f17166, 80baa5d)
  • Options starting with a single dash are now read as GNU ld reads them. For example, -entry=main was read as -e ntry=main. (#1671, #1670) (830a860)
  • --dynamic-list-data, --lto-pseudo-probe-for-profiling and --thinlto-index-only no longer consume the next argument, and --no-color-diagnostics is now accepted. (2ca893e, 04b493e)
  • If a version script lists a symbol in more than one version node, the first one now takes precedence, as in GNU ld and lld. (b7048f5)
  • Fixed relative paths with -C, --chroot and --repro. (e3bc349, 04e7dd8, a368d22)
  • mold no longer reserves 8 GiB of virtual address space at startup, so it works under ulimit -v. (cc69390, b18be91)
  • MOLD_JOBS now works if XDG_RUNTIME_DIR is an empty string. (8a360ff)
  • Files created by --separate-debug-file no longer contain a .gnu_debuglink section. (#1656) (b56649e)
  • mold no longer creates the meaningless __start_EHDR, __stop_EHDR, __start_PHDR and __stop_PHDR symbols. (0ee71d3)
  • [AArch64][PPC32][ARM32] Fixed calls to static functions in other sections through range extension thunks, which jumped to wrong addresses in large programs such as the ARM64 debug build of Chromium. (4165d0e, 9b91621)
  • [AArch64] Added support for more relocation types, such as R_AARCH64_TSTBR14 and R_AARCH64_GOT_LD_PREL19. (96d0282, a4b64d8)
  • [ARM32] Added support for more relocation types, such as R_ARM_ALU_PC_G0 and R_ARM_THM_PC12, and fixed -r output for big-endian ARM. (c0f9cd6, 4c9aad3, 4c26f16)
  • [ARM32][i386] -r no longer corrupts instructions referred to by some branch and TLS relocations. (1b17bdf)
  • [RISC-V][LoongArch] Fixed calls to functions folded by --icf=all when relaxation shrinks them, and R_RISCV_64 and R_LARCH_64 relocations in 32-bit objects. (52febe9, 5b22233)
  • [RISC-V] Fixed TLSDESC with object files created by Clang 18, --emit-relocs with TLSDESC relaxation, the EF_RISCV_TSO flag, R_RISCV_ALIGN in -r output, and overflow checks for 32-bit PC-relative relocations. (fdf8422, 7c8b805, 6b60f75, 4ba7792, 85d55f3)
  • [LoongArch] Added support for TLSDESC in the extreme code model, and fixed wrong values of *64_PC_HI12 relocations and spurious overflow errors for TLS relocations. (a36a161, 8133938, 13e6cc0)
  • [PPC32][m68k] A GOT too large for the 16-bit offsets that -fpic code uses is now reported as an error instead of being silently truncated. (acc8854, 614e2a0)
  • [PPC64] Fixed IFUNC calls in statically-linked executables and @got references in hand-written assembly, and mold now synthesizes the _savegpr0_* family of functions for PPC64V1 as well. (d3b2a74, b34a308, efda2fc)
  • [SH4] Fixed a crash when calling a function that returns a structure through the PLT, and C++ exceptions in programs linked from -r output. (d9cf1f0, 92161dd)
  • [SPARC64] Fixed branch instructions using R_SPARC_WDISP16, and R_SPARC_OLO10 in -r output. (6df3fd2, 269fbb9)

Acknowledgements

mold is an open-source project, and we accept donations via GitHub Sponsors and OpenCollective. We thank everyone who sponsors our project. In particular, we would like to acknowledge the following organizations and people who have sponsored $32/month or more during this release cycle:

The Daily Front Page 10 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Apple’s Agent Problem
article

Apple and a hacker's future

by maguay·▲ 232 points·203 comments·stratechery.com ↗
The question, however, is whether what they are designed for is the future I am barreling towards

Apple and a Hacker’s Future

My computer got hacked, which is always embarrassing to admit, because it was my fault; the vulnerability that was exploited is detailed in this Ars Technica story:

Dutch officials have warned that a high-severity macOS vulnerability that allows attackers to execute malicious code is under active exploitation. “The NCSC has received a notification indicating that active abuse of this vulnerability has been observed on multiple systems on which port 5900 was accessible from the Internet,” the Netherlands National Cyber Security Centrum warned earlier this week. “In all these cases, root had been accessed on the affected system and a Monero crypto miner had been placed.”

The vulnerability, tracked as CVE-2026-65400, received a patch from Apple last week for macOS Tahoe, Sequoia, and Sonoma. The vulnerability, with a severity rating of 7.1 out of 10, stems from a bug in the macOS screen sharing capability, which allows a remote party to view the screen and control the keyboard and mouse while a machine is turned on. A flaw in the “state management,” which keeps track of preceding events, user interactions, variables, and other system states, is the underlying cause.

A video of the exploit in action can be found here. Details of CVE-2026-65400 became public at last week’s Black Hat security conference. Apple said last week that CVE-2026-65400 “may” allow an attacker without credentials to gain access to a Mac. It’s unclear why Apple hedged, but softening language is common among most tech developers when disclosing vulnerabilities. Apple credited security firm Bynario for reporting the vulnerability.

The computer in question was my always-on Mac Mini that runs nothing but Claude and Codex; the first thing that makes this story interesting is that that was my saving grace.

Agent Protection

I have discussed, in both Writing Things Down and in several episodes of Sharp Tech, Gecko, the agent that I have built for the people that work with me. It’s awesome, but purposely constrained in capability and in what it can access. My real agent is a dedicated Claude Code thread that writes down all of my ideas and tracks the status of the myriad of projects I’ve spun up over the last few months.

There are a few reasons why I use Claude for this functionality, even though I’m not a big fan of Claude-speak: Claude in its Code harness seems to handle wide-ranging discussions better than Codex, and it follows my instructions about writing things down in the way I want to more gracefully. Code also has a persistent monitoring tool that I utilize as an inbox to capture interactions with a status board I built to visually track everything I have written down, as well as interactions with a Telegram bot (OpenAI’s new Dots achieve some of this functionality, which has been sorely needed in ChatGPT/Codex).

Said monitoring tool stands down every 30 minutes, so my agent restarts it on a schedule; that is what triggered an URGENT notification from Claude:

>Urgent: the Mac mini looks compromised. Someone with admin (root) access has planted a crypto-miner on it. I have stopped running commands, and I have not changed or deleted anything.  >What I found:  >- A hook in the shell startup file. /etc/zshenv is a file that every new terminal and every one of my commands reads first. It now tells the machine to quietly run /var/tmp/.xmr with admin rights. >- The miner script. /var/tmp/.xmr is a script that downloads a crypto-mining program and sends its earnings to an outside wallet and server. Its comments are in Chinese and mention earlier batches, so it looks like an automated campaign, not something aimed at you in particular. >- Faked dates on both files. Both are owned by root and dated Dec 31 1969, which is a sign the dates were wiped on purpose. >- When it happened. Both files were changed during this session, between two of my routine restarts of the watchers. The startup file reported no error before that point.

Claude had more diagnostic information, unilaterally stopped executing all commands, and noted that my account could now run admin commands without a password, which it assumed was how the files were written; it then had a number of suggested next steps to address the problem. The one I ignored was its recommendation that I not invoke Claude anymore; in fact, I used Claude to root out the malware — we eventually found the exact four second period where it gained access — create a tool to watch for it in the future, and then wiped the Mac Mini.

All of this happened before I found the Ars Technica article detailing the vulnerability, and it was pretty remarkable. I understand that people are nervous about giving these agents access to one’s computer — as I noted, the Mac Mini in question has nothing on it except for Codex and Claude — but in this case you could make the case that I would have been in much more trouble had I not had an agent running persistently.

Apple Protection

Apple doesn’t seem too happy about agents; last week the company’s developer site released a note entitled Updates to Full Disk Access in macOS; I’m going to quote it in full:

We give developers powerful APIs to build incredible capabilities into their apps for Apple products, backed by a set of controls designed to protect users’ private data. Full Disk Access largely sidesteps these controls in order to allow backup apps to function properly on the Mac. Some developers are using Full Disk Access in ways that could put users at risk, exposing everything on their systems—including files, mail, messages, and even browsing history—without users’ full knowledge and understanding. For communication apps, this can also compromise the privacy of the people users are communicating with.

Going forward, we will introduce additional controls to ensure that users who genuinely wish to grant an app this extraordinary level of access can only do so with very explicit user action. Addressing this is critical. As AI agents become increasingly capable and autonomous, the risks associated with this level of access will grow substantially. We are committed to ensuring users clearly understand these risks before granting such access, so they can make informed decisions about their own data and privacy.

To say that I’m nervous about what Apple’s solution will entail is a massive understatement. There is one aspect in which the Mac is the perfect agent host: Apple has, for decades, invested in a combination of scriptability, automation, and accessibility APIs (these are very often the same thing) that makes it remarkably well-suited to computer use. Then there is the fact that macOS is a certified Unix system; this means that agents — which are perfectly suited to the command line — have access to the entire universe of tooling built for Unix systems. And, of course, Mac hardware is amazing.

The problem is that for my particular use case — a headless, always-on Mac Mini that I primarily access from other computers and my phone through the ChatGPT and Claude apps — macOS is incredibly hostile. The biggest issue is GUI-only permission prompts that are invisible to software running on said computer, including agents.

These permission prompts are a part of a macOS subsystem called Transparency, Consent, and Control (TCC), although Apple doesn’t seem to use this name anymore. There are a whole host of things on your Mac that are covered by TCC — the list only gets longer with every OS release — and you have to explicitly approve access to the covered items for every app that wants to access them. If you’ve been prompted for permission to use the Camera, or, much more annoyingly, access the Desktop or Downloads, you’ve encountered TCC.

This system is annoying but manageable on your primary Mac; it’s a disaster on a headless Mac running agents, for two reasons. First, agents write new programs all of the time, and in my case, those programs need access to devices on my network (SMB shares, for example, trigger a TCC warning). What I need is a permission layer for agents, not the programs they create; TCC is operating at the wrong level of abstraction.

Second, the TCC subsystem exposes its prompt in a protected space that no program can see; that means that programs silently fail and the agents don’t know why; what I have to do is remember that there is probably a permissions prompt on screen, log into the Mac Mini with screen-sharing software, and click OK.

There are in fact good reasons for this. The goal of the TCC subsystem is to protect you from malware accessing your computer nefariously; if the prompts were accessible by software running in userland then malware could work around it. Again, though, I am running a computer that is purpose-deployed for agents: for my use case TCC is nothing but a headache — one that indirectly led to my being hacked.

Apple Frustration

Again from Ars Technica:

As noted by the NCSC, the vulnerability is being exploited when port 5900 is exposed to the Internet. When screen sharing is turned on, the macOS firewall opens the port. Routers and dedicated firewalls generally block the port unless configured to override that setting. Security practitioners generally advise Mac users to keep the port closed even when using screen sharing and to instead connect over a VPN or through SSH tunneling. The alternatives require actions that aren’t within the capabilities of most users.

The safest practice is to block screen sharing, enable it only when screen sharing is needed, and to turn the feature off once a session has ended. Screen sharing can be turned on or off by accessing System Settings > General > Sharing and toggling the switch for Screen Sharing. Of course, installing last week’s security update is also a must.

Obviously I should have — and will be — using a VPN going forward (the foundation of my entire approach to security is Tailscale); what I will note, however, is that TCC basically leaves me no choice but to have screen sharing enabled if I want to actually use my Mac Mini in the way I want to use it. I use screen-sharing constantly — including from my phone — and almost every time it’s to click “OK” on a stupid prompt that I’ve long since stopped taking seriously; the reason I didn’t depend solely on Tailscale from the get go is that I wanted a secondary way to reach the Mac Mini (which should have been SSH tunneling; again, this is somewhat embarrassing and my fault).

What really irks me about this episode, however, is how Apple released the fix. Obviously I know that you should always keep your computer up-to-date for security purposes; that’s why I have all of my computers set to automatically install security updates.

What I didn’t understand is that this setting does not in fact apply to most security updates. CVE fixes almost always arrive in point releases; in fact, the most recent point release was about fixing this bug. In fact, I suddenly realized that I had been leaving myself more exposed than I should have been for years, under the mistaken assumption that checking “Install…security updates automatically” would in fact install security updates automatically.

I am admittedly being pedantic here; at the end of the day I hadn’t installed the point release promptly enough. Still, it does bug me that a company that is so concerned about access to my Desktop wasn’t very concerned about how a pretty important setting reads to a fairly sophisticated user. Again, this is my mistake, but the mistake was an honest one downstream of trusting Apple to call a security update a security update, particularly if they give the option to automatically install them.

That’s trust they have by-and-large earned; what is increasingly frustrating is that that is trust they increasingly demand, and the scope of those demands is continually increasing. It may seem silly to complain about the labeling of an update, but if you’re going to demand permission for accessing a network share can you at least patch my computer when I explicitly gave you permission to?

This, by extension, is why the note about full disk access is unnerving. I can understand that users may not understand that granting an agent full disk access means that that agent can read your iMessages (for now — I bet that the iMessage store will be encrypted in the near future, a la iTunes in the 2000s); other users, however, may want exactly that. Or, like me, they might want to actually use a Mac as their own personal computer, not as an Apple-managed device increasingly akin to an iPhone. Maybe this episode shows I’m too dumb to risk that; maybe it just means Apple and I are, after many years together, speaking past each other.

Home Visions

Last week Mark Gurman wrote an article on Bloomberg entitled Apple Is Finally Ready to Enter Its Next Big Category: the Smart Home:

Apple Inc. plans to make its long-delayed push into the smart-home market on Oct. 13, marking a critical product expansion for the company under new Chief Executive Officer John Ternus. At the center of the strategy is a smart-home hub code-named J490, according to people familiar with the matter. Apple also plans to announce the first update to the HomePod mini since that device’s 2020 debut and its first new TV set-top box since 2022…

The products also serve as a showcase for Apple’s new Siri AI assistant, technology that the company spent years developing. The revamped Siri suffered numerous delays, and the smart-home devices should help spotlight Apple’s efforts to finally catch up in artificial intelligence. The home hub will take the form of a roughly 6-inch square display, with versions that can be mounted on a wall or placed on a countertop, according to the people, who asked not to be identified because the products haven’t been announced…

Apple envisions customers placing several of the displays throughout their homes. They could be used to control thermostats, door locks and other connected products, as well as for video calls, intercom-style communication, music playback and viewing slideshows of photos stored in Apple’s iCloud service.

That wasn’t the only home automation related announcement last week; Muse creator Nat Friedman posted on X:

I get, very acutely, that I am not representative of the general population. I actually use agents, for one. More than that, I’m not a target customer for Muse: I’m more interested in building my own agent than in using Meta’s; one of my current projects is the construction of a small home electronics lab to make some of my own agent-controlled gizmos.

With that noted, what struck me about Gurman’s article is just how unenthused I am by an Apple smarthome product. Some of this is fatigue from a decade of Siri disappointment and skepticism about the company’s ability to deliver on a voice-centric product. More than that, however, I bristle at the idea of introducing Apple’s constraints to more parts of my life.

Those constraints aren’t just about things like full disk access. To the extent that Apple delivers on integration with things like thermostats and door locks is the extent to which they work with 3rd-party device makers; the problem is that third party device makers mostly suck, particularly from a software perspective. Even if Siri were perfect, Apple will have the challenge of delivering an experience that isn’t defined by the lowest common denominator.

What I’m much more interested in is controlling the software layer myself. The fact of the matter is that with AI you can decompile almost all existing software — there is a revolution happening in gaming over the past few weeks, as game after game is decompiled to source and ported to any platform you wish — and you can write your own. That means my software that interacts with my agent in the way I want it to for everything; that’s way more exciting than praying Apple delivers the right API and that 3rd-party developers don’t suck.

The App Limitation

This, by the way, is a problem facing Siri; I wrote after the recent iPhone event and Ternus’ vision of the “Intelligent Personal Hub”:

What is most interesting, however, is how the biggest advantage Apple has traditionally had may be a hindrance…it’s extremely impressive that Apple claims 300,000 apps work with Siri. Note, however, that the implication of it being “easy for developers to adopt new capabilities” is that developers have to actually put in the work — that’s work in addition to updating their UI for Duo.

In a world where everyone has to convince developers to build integrations, this wouldn’t be an issue. However, this is where browser use looms large: to the extent that agents can just use the web is the extent to which they get an integration with basically everything for free, and it’s Apple, with its dependency on developers plugging into APIs, who is at a disadvantage…

In Apple’s vision, the utility of Intelligence is defined by its ability to augment your existing workflow. Thus the reference to updating your calendar and reminders. It’s very possible, however, that the better workflow is to outsource a lot of work that used to happen in apps to the agent directly. What’s better, using a structured reminders app that you have to check, or simply being reminded directly by an agent? In truth the answer will likely vary by person, but it’s worth pointing out that Apple is so married to the app paradigm that they probably never even considered the alternative.

Apps were amazing, and a better experience than what came before; that doesn’t mean they are the best experience, and anyone who has seriously used an agent knows exactly what I mean. Apps get in the way, which is to say that integrating with them is to make your agent worse; I don’t want a different UI per app, when I have at my disposal true UI — the Universal Interface for everything digital.

This is where the Muse Gadgets program is a stroke of genius. Meta is seeding an entire ecosystem of devices, some of which might become real products, and it’s completely open source. The payoff isn’t in selling devices; it’s in Muse being the interface for everything.

A Hacker’s Future

21 years ago Paul Graham wrote Return of the Mac:

All the best hackers I know are gradually switching to Macs. The reason, of course, is OS X. Powerbooks are beautifully designed and run FreeBSD. What more do you need to know?…

With OS X, the hackers are back. When I walked into the Apple store in Cambridge, it was like coming home. Much was changed, but there was still that Apple coolness in the air, that feeling that the show was being run by someone who really cared, instead of random corporate deal-makers.

So what, the business world may say. Who cares if hackers like Apple again? How big is the hacker market, after all?

Quite small, but important out of proportion to its size. When it comes to computers, what hackers are doing now, everyone will be doing in ten years. Almost all technology, from Unix to bitmapped displays to the Web, became popular first within CS departments and research labs, and gradually spread to the rest of the world.

As someone who switched to the Mac in 2004, a year before Graham wrote his article, this was edifying: “I just switched to the Mac, I guess I’m a cool hacker”. In truth, the Unix part didn’t matter much to me; I preferred the design and the UI, and really wanted to try GarageBand. And, over the ensuing years, I appreciated the extent to which the Mac just worked — slower than the alternatives at first, then at parity, and then, with Apple Silicon, better than anything else.

The thing about AI, however, particularly agents, is that they make anyone a hacker. You really can do anything now, if only you have the volition and the ideas, and once you embrace that, a walled garden feels less like protection and more like a prison.

I’m not, to be clear, predicting Apple’s downfall; I’m not even changing my computer or phone. What is surprising to me, however, is that not only am I uninterested in the company’s home device, I can, for the first time, envision a future where I don’t buy Apple by default. Indeed, this already happened: even before this incident I had already purchased a new server, which will run Linux; I will never put a Mac in a rack again.

That’s fine for Apple, of course; that’s not what their computers were designed for. The question, however, is whether what they are designed for is the future I am barreling towards, one where agentic abstraction both renders traditional interfaces relics even as it makes computing everywhere more accessible than it has ever been, where the limit is not a developer building for scale but my own imagination building for myself.

The Daily Front Page 11 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Plague Watch
article

US closely monitoring case of lab worker who possibly died of plague in Siberia

by tosh·▲ 210 points·221 comments·theguardian.com ↗
The US secretary of state, Marco Rubio, has said the US is closely monitoring the case

Quarantine measures in place in several hospitals in eastern Russia amid uncertainty over death of Darya Shipilova

A close-up portrait of Darya Shilipolva taken outside near trees and under a blue sky

Darya Shipilova, who worked at a plague research institute in Siberia, died on the night of 2 October at a regional hospital in Shelekhov, Russia. Photograph: Social Media

The US secretary of state, Marco Rubio, has said the US is closely monitoring the case of a Russian laboratory worker who died last week after a reported accident at a plague research institute in Siberia.

“We’re watching and monitoring it closely,” Rubio said on Monday before leaving for a trip to Europe. “I ⁠don’t think it’s cause for alarm, but it is cause for focus and a cause just to keep an ⁠eye on it.”

Darya Shipilova, a 28-year-old employee at the anti-plague institute in the city of Irkutsk, became ill at work. She died two days later on the night of 2 October at a regional hospital in the nearby town of Shelekhov.

It remains unclear how she became unwell. Unconfirmed reports in Russian media have suggested Shipilova may have been infected after a mishap at the laboratory. Officials have not publicly confirmed that account.

Local media have reported that the institute has subsequently been locked down, with staff forced to sleep on the floor and on chairs. “They’ve been isolating everybody since Friday – more than 60 people,” one relative, Roman, told the news portal Siberia.Realities.

He said family members were allowed to drop off food at a checkpoint while tests were carried out inside the building. Similar quarantine restrictions have been placed on several other hospitals in and around the city.

Rubio, citing what ‌Russians have released about the death, said it seemed a worker in the lab became ​infected and there was concern the disease may have spread internally.

“There’s very limited travel between the US and Russia, obviously,” he said. “But like anything else, something like that gets out, it just quickly spreads.”

Senior Russian officials have added to public disquiet by sending conflicting messages. Alexey Tsydenov, the head of the Buryatia region, which neighbours Irkutsk, initially wrote that Shipilova had died of plague, before editing his post to say she had “possibly” died of the disease.

Rospotrebnadzor, Russia’s health watchdog, said Shipilova died from “pneumonia of unknown aetiology”. It insisted that tests found no micro-organisms linked to her professional work and described the “sanitary and epidemiological” situation in the area as stable.

Authorities in the nearby city of Baikalsk briefly urged residents to avoid travelling to Shelekhov and surrounding settlements after what they said was unofficial information about a possible plague infection. They later deleted the post from social media.

“There are no obvious changes to daily life on the streets, but people are worried and anxious. Locals are angry that they are not being told anything,” said Elena Trifonova, a journalist with People of Baikal, an exiled Russian media outlet specialising in Siberia.

Despite the lack of a confirmed diagnosis, precautionary measures appear to have been introduced across the region. The US-funded Radio Free Europe/Radio Liberty reported on Monday that several hospitals in Irkutsk had been placed under quarantine.

The outlet confirmed that staff from Shipilova’s workplace, the Irkutsk Anti-plague Research Institute of Siberia and the Far East, had been kept inside the institute since 2 October.

Patients at Irkutsk city clinical hospital No 1 and the Ivano-Matreninskaya children’s hospital said relatives were not being allowed to visit and people inside were not permitted to leave.

On social media, local residents described some of the precautions being introduced.

Ulyana Gavryunina, who went on Monday to one of Irkutsk’s main maternity hospitals for a routine check-up on Monday, said doctors refused to allow her mother in, citing a quarantine imposed over the suspected plague case. Gavryunina said staff member checked her for flu-like symptoms and asked her to fill out a screening form for infections, on which “plague” was listed. She posted a photograph of the form on Instagram.

Elsewhere, a mask requirement was introduced at the Irkutsk aluminium smelter in Shelekhov. The plant’s director, Artyom Fominykh, called it a preventive measure, saying: “Better safe than sorry.” Over the weekend several public events in Irkutsk were cancelled.

Shipolova’s death has prompted intervention from senior federal health officials. Anna Popova, the head of Rospotrebnadzor and the country’s chief sanitary doctor, travelled to Irkutsk on Friday.

She attended an emergency meeting of the regional sanitary and anti-epidemic commission over what officials called a suspected case of a “particularly dangerous infection”.

Igor Kobzev, the governor of the Irkutsk region, urged residents to remain calm after meeting Popova to coordinate the response. “All identified contacts have been placed under medical observation. As of today, none is showing signs of illness and laboratory tests have returned negative results,” he wrote on Telegram.

Kobzev made no reference to reports that a laboratory worker had died.

US politicians have raised concerns about the incident, which follows longstanding and unfounded allegations by the Kremlin that Ukraine has secretly carried out biological weapons research with the support of Washington.

A Republican representative, Don Bacon, a senior member of the House armed services committee, wrote on social media: “I remember hearing from anti-Ukraine voices about their so-called bio labs. It was Russian disinformation ops at their best. But in reality it is Russia with the bio labs.”

Plague remains endemic in parts of Siberia and the Russian far east, where the bacterium persists naturally among wild rodents and their fleas.

But human cases in Russia are rare. Before the suspected Irkutsk case, the country’s last recorded human infection was in 2016, when a 10-year-old boy in Siberia’s Altai Republic contracted plague after helping butcher a marmot.

“This case here seems like a rare lab accident and is unlikely to go much further,” Prof Ian Jones, a professor of virology at the University of Reading, in the UK, said. “Although it is true that pneumonic plague is directly transmissible, the contacts of the primary case are known and can be treated if they show any sign of infection.”

He added: “Plague carries a huge history and is still present in many parts of the world, including Russia, but the living conditions associated with previously spread plague are no longer generally true, antibiotics are available and its potential is therefore limited.”

The Daily Front Page 12 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — The Plain Text Ledger
article

Plain text is still one of the best technologies we have

by speckx·▲ 184 points·97 comments·deadparrotbbs.com ↗
There are not many computer file formats I would trust to still be readable fifty years from now, but plain text is one of them.

There are not many computer file formats I would trust to still be readable fifty years from now, but plain text is one of them. That may sound like faint praise. A text file cannot embed a spreadsheet, preserve elaborate page layouts, run a presentation, or provide many of the conveniences we expect from modern applications. What it does instead is store text in one of the simplest and most widely understood forms in computing, and that simplicity is a large part of why it has lasted.

Almost Nothing to Go Wrong

The Unicode Standard defines plain text essentially as a sequence of character codes, without the additional formatting information associated with rich text. Fonts, colors, layout, and similar presentation details belong somewhere else.

From a user’s point of view, the important part is simpler: the file contains the text itself without requiring a particular application to make sense of it. I can create a text file on Linux, copy it to a Windows machine, put it on a web server, open it in a terminal, search it with command-line tools, edit it with any number of programs, or send it to somebody using an entirely different system. Very little about the file depends on how it was created.

That is different from many document formats, where the information is closely tied to the application or family of applications that understands the format. Sometimes that is harmless. Sometimes the format is well documented and broadly supported. In other cases, opening an old file means hoping that suitable software still exists.

Plain text has very little of that baggage.

We Have Been Using It Forever for a Reason

Plain text is not some forgotten technology that needs rescuing. It remains part of the basic plumbing of computing.

Source code is generally text. Configuration files are often text. Log files are commonly text. Unix and Linux systems are full of text files. Much of the machinery behind the web also involves text in one form or another. HTML, XML, JSON, CSS, shell scripts, programming languages, configuration formats, and plenty of other things are built around characters that humans can inspect.

These are structured formats rather than ordinary prose, of course. An HTML document is not the same thing as a note in a .txt file. The similarity is that the contents are still visible. Open the file in a basic text editor and you can see what is there, even if you do not understand every part of it.

That has practical value. When something goes wrong with a text configuration file, I can inspect it directly, copy it, compare versions, search for a particular setting, or make a backup without needing the program that created it. Data that remains intelligible outside its normal application is much easier to troubleshoot and preserve.

Plain Text Plays Well With Others

One of plain text’s greatest strengths is that an enormous collection of tools already knows how to work with it.

On a Unix-like system, a text file can be handed to grep, sed, awk, sort, diff, and many other utilities that have existed for decades. A script can process thousands of files without pretending to be a human clicking through menus.

The advantage is not limited to the command line. Graphical editors, programming environments, note-taking applications, file managers, search tools, browsers, and countless other programs can work with text too. The real advantage is that the information is not tightly coupled to one interface.

Modern software often takes the opposite approach. An application may determine where your information lives, how it is organized, how it synchronizes, how it is searched, and what other software is allowed to touch it. Those systems can provide useful features, but they also make the application increasingly central to the data.

Plain text leaves more of those choices to the user.

Markdown Found a Useful Middle Ground

The obvious weakness of plain text is formatting. Headings, emphasis, links, lists, quotations, and other structures make documents easier to read, and a basic .txt file does not provide a standard way to express most of them.

Markdown is a practical compromise. It is a plain-text format for structured documents, drawing on conventions that were already familiar from email and Usenet. It was introduced in 2004, and variations of it are now used for software documentation, websites, notes, books, and many other kinds of writing.

Its real strength is that the source remains useful even if the Markdown processor disappears. A heading still looks like a heading. A bulleted list still resembles a list. A link still contains both its description and destination. The formatting syntax is visible rather than buried inside a binary structure.

That is a good example of adding useful capability without giving up the main advantages of plain text. The rendered output may be convenient, but the source file remains ordinary text.

Text Ages Surprisingly Well

Longevity may be plain text’s strongest argument.

Computer history is full of abandoned file formats and applications. Sometimes recovering an old document means locating obsolete software, finding an import filter, running an emulator, or converting through several intermediate formats.

Text files are not completely immune to compatibility problems. Older files can have character-encoding issues, and differences in line endings have caused irritation for years. Still, these are usually manageable problems compared with trying to recover information from an obscure proprietary format.

If I find an old text file, there is a very good chance that some program on a current computer can open it. Even if the formatting is crude or the encoding needs attention, the words themselves are generally recoverable.

Modern Unicode has also made plain text far more capable than the old idea of ASCII text containing little more than English letters, numbers, and punctuation. Plain text today can represent writing systems and characters from around the world while retaining the same basic idea: the file contains encoded characters rather than a proprietary presentation format.

Simple does not have to mean primitive.

It Is Also Easy to Own

The advantages of plain text become even more noticeable as software moves toward accounts, cloud storage, synchronization services, and subscriptions.

A text file can simply exist in a directory on my computer. I can back it up with the rest of my files, synchronize it however I want, put it under version control, copy it to another machine, or store it on a server I control. None of that requires the company that made my editor to stay in business or continue supporting a service.

That does not make every note-taking service or cloud application a bad idea. Specialized applications provide features that plain text alone cannot provide easily. Collaboration, databases, embedded media, complex formatting, and relationships between different kinds of information all have legitimate uses.

There is no benefit in forcing every kind of data into a .txt file. The useful distinction is whether the additional complexity solves a real problem or simply becomes another dependency.

When plain text is sufficient, it removes a surprising number of things that can later get in the way.

The Limitations Are Real

Plain text is not the answer to everything.

I would not want to replace a photograph with a text description of its pixels, and I do not want a financial workbook turned into a pile of numbers that requires me to reconstruct all the formulas manually. Rich documents exist because presentation and structure sometimes matter.

Applications also provide useful abstractions. A database can enforce relationships that a directory full of text files cannot. A word processor can handle page layout that would be tedious to reproduce manually. Specialized software exists for good reasons.

The problem is not using richer tools. It is assuming that richer tools are automatically better even when the job does not require them. In a surprising number of cases, the simplest adequate representation remains the most durable one.

Boring Is a Feature

Plain text is one of those technologies that becomes almost invisible because it works so reliably. It has no company trying to increase engagement, no account requirement, no subscription tier, and no service that can be discontinued when the business model changes.

It is portable, inspectable, searchable, scriptable, easy to back up, and remarkably resistant to obsolescence. Those qualities are not exciting, but they are useful, especially over long periods of time.

After decades of watching software and file formats come and go, I have developed a fair amount of respect for technologies that do less and survive longer. Plain text does not solve every problem, and it should not. What it does provide is a stable way to store information without requiring very much from the software around it.

For something so basic, that is a considerable achievement.

The Daily Front Page 13 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — At Home With Light
article

The lamps in my house

by farslan·▲ 159 points·75 comments·arslan.io ↗
I have a thing for lamps.

The lamps in my house

I have a thing for lamps. Especially designer lamps from the past. I occasionally share them on X and Instagram, and people always ask me about the brands and models. I love lamps so much that I designed one myself. So I decided to give a tour of the lamps I own.

Before I go into each one, I should say that none of these are cheap. Are they worth it? Probably not for their price, but for me they are worth every penny. At a certain point, it becomes more like collecting, and collecting things is very different from just having a lamp to illuminate a room. The lighting industry is a huge ecosystem though, and nowadays you can get really nicely designed lamps from IKEA for maybe a tenth of the price. Also, most of these can be found for very good prices at vintage stores or fairs.

Anyway, here are my lamps in no particular order. All of the photos were taken in my own house:

Artemide Tolomeo Mini

The Tolomeo was designed by Michele De Lucchi and Giancarlo Fassina in 1987. De Lucchi is one of the big names in Italian design and was also part of the Memphis movement. The lamp won the Compasso d’Oro in 1989.

It is probably one of the most copied desk lamps ever made. IKEA and many other companies have made lamps that look very similar. A reader of my blog also sent me a photo of the old Apple Industrial Design studio, where you can see several Tolomeos on the desks.

It is simple, easy to move, and probably one of the best lamps you can have on a work desk. Lastly, I also designed a small adaptor for mine, so I can attach it directly to my USM Haller desk.

Tizio Micro

Richard Sapper designed the Tizio in 1972. He is one of my favorite industrial designers. He later designed the first IBM ThinkPad, as well as the famous 9090 espresso maker for Alessi. Tizio means “dude” in Italian.

The Tizio started because Sapper wanted a better lamp for his own desk. There are no wires running along the arms because the arms themselves carry the electricity. Counterweights keep everything balanced, so you can move the lamp with one finger and it stays there.

The small red details are Sapper's unique signature. He often used a little bit of red on black products, for example the red TrackPoint on the ThinkPad. The Micro is a smaller version of the original Tizio, and there are several versions you can choose from.

Akari 1A

I got this lamp secondhand from Germany, and a friend brought it to me. It's made of washi, which is a traditional Japanese paper. It is thin, soft, and slightly warm in color, which gives the light a very gentle glow.

The Akari 1A was designed by Isamu Noguchi (a very famous Japanese-American designer). He started the Akari series in 1951 after a visit to Gifu, a city known for its paper lanterns. He used washi because it softened the light and also allowed him to create very light, sculptural shapes. Akaris are really more like sculptures, which Noguchi is also famous for!

Fun fact: “Akari” means light in Japanese, both as illumination and as lightness. The 1A is one of the earliest and simplest shapes. I like Akaris so much that I have a few of them sprinkled around my house.

Akari 3A

The Akari 3A is similar to the 1A, but it is taller, with longer legs and wooden trim at the top and bottom. It has a slightly awkward size. At 56 cm tall, it feels too short to sit directly on the floor, but also a little too large for a normal desk. I think it works best on a low table, sideboard, or cabinet.

Akari 16A

This was the first Akari I bought. I initially had it in my office, but later moved it to our bedroom. It has a very unique shape, but at the same time it almost disappears into the room. It feels incredibly light. One nice thing about Akari is that every lamp is still made by hand at Ozeki, a family-run workshop in Gifu, Japan. They still use the traditional methods that were used when Noguchi started the series.

Akari 75A

The Akari 75A is the biggest lamp in my house. It is roughly 75 cm across and completely fills the space. This is the lamp that replaced the Akari 16A in my office. Compared to the 16A, the 75A really fills the room and has a presence. Another fun fact: every real Akari carries a small red sun-and-moon stamp, which is the mark of authenticity. Noguchi designed more than 100 different Akari models during his lifetime.

Louis Poulsen PH 5

I first noticed the PH 5 in Another Round, the Danish film about teachers who start drinking heavily. The family was sitting around the dinner table, and the PH 5 was hanging right above them. Later I saw one in Dieter Rams’ house, and that was it for me. I’m a huge fan of him.

The PH 5 was designed by Poul Henningsen in 1958 and is probably one of the most famous Danish lamps ever made. It is also very common in Danish homes. The nice part is that you never really see the bulb directly, so the light always feels soft. The “5” comes from the 50 cm shade, and the small red and blue parts inside help make the light feel warmer.

Louis Poulsen PH 3/2

Henningsen actually created the three-shade system in 1925. The PH 3/2 was the first lamp to use this system, and it won a gold medal at the Paris exhibition that same year.

It's made out of glass (unfortunately, it breaks easily if you are not careful), and the glass is mouth-blown. I actually broke it by accident and had to wait months for a replacement. It's shiny on the outside and matte on the inside. The famous PH 5 came more than 30 years later, though. It uses the same idea of several shades to make the light softer and more comfortable.

AJ Wall Lamp

The AJ Lamp is another design icon. We have the wall version at home. Arne Jacobsen designed it in 1957 for the SAS Royal Hotel in Copenhagen, where he designed almost everything, from the furniture down to the cutlery.

Fun fact: that same cutlery later appeared in 2001: A Space Odyssey. What I like most is that you can tilt the lamp. I sometimes point it towards the wall for soft, indirect light, and when I read, I simply point it towards the book.

Lampe de Bureau (Jean Prouvé)

Jean Prouvé is one of my favorite designers. He was a French designer and metalworker. He is most famous for his simple, practical furniture like the Standard Chair. He designed the Lampe de Bureau in 1930 for the student residences in Nancy. It is made from a bent sheet of steel and looks more brutal/engineered than other lamps. That is typical of Prouvé; most of his work looks like that. Nowadays you can get it from Vitra in its original colors.

Chispa (Marset)

Joan Gaspar designed the Chispa in 2020, inspired by old garage lamps with a metal cage around the light. “Chispa” means spark in Spanish. It is rechargeable, water resistant, and has three levels of light, so I move it around the house quite a lot. We also use it in our garden in the summer.

Kismas Lamp 01

Kismas is a small design studio from Vilnius, Lithuania, started by designer Ramūnas Minkevičius. “Kismas” means change or transformation in Lithuanian.

The Lamp 01 uses real glass blocks from Soviet-era buildings from the 1970s and 80s, with a light underneath. It also comes with film and theater filters that you can place inside to change the color of the light, though I find that very cumbersome. I think it's a very artistic lamp, but not very functional.

Tokio Lamp

I discovered this one while walking in Copenhagen with my wife, when I saw it through a shop window. Shigeaki Asahara designed it in 1980 for the Italian company Stilnovo, with a shade that looks like a mailbox. It was forgotten for decades until the Danish brand “Please Wait to be Seated” brought it back in 2020.

Unfortunately they didn't have it in stock that day, so I later shipped it to Germany, and from there brought it with me to Ankara, Turkey. It's one of my most unique lamps.

Vision 20/20 Floor

Made by DCW éditions from Paris, and named after the eye test at the optician. The base slides under a sofa, and it has two lights, one pointing up and one down, each with its own dimmer. It's very functional and made especially for reading. It sits next to my Eames chair, and I turn it on whenever I'm deep into reading a book.

HAY Apex Floor Lamp

John Tree designed the Apex line for HAY in 2023. It's inspired by the classic banker's lamp. The lamp shade is a single sheet of steel folded over the bulb. For the floor version I picked up a black one. The nice thing about the metal shade is that it rotates 360 degrees. That way you can reflect the light off the wall and create a nice diffused/indirect light.

HAY Apex Clip Lamp

The same folded shade, but this time in green, with a clip instead of a stand. Because the clip was ugly and hard to mount on my Vitsoe 606 e-tracks, I did something myself. I designed a 3D-printed attachment. It took a few versions to get right, but now it looks really nice!

Block Lamp

And finally, my own design. I made it in January 2025 for the shelves of my espresso bar. It's a single 3D-printed piece with no glue or bolts, and the front handle can be pulled, pushed or rotated. The best thing about the lamp is that it can be rotated and used in three different ways. Of course, because it is a 3D print, I'm limited in the choice of material. I still have some ideas for it, like adding a battery and making it portable, or using a CNC-milled or wooden housing.


That's it. The world of lighting is incredible. There are design companies that specialize only in lamps. I'm mostly interested in sleek, minimalist and iconic designs (such as the Akari, Tizio, AJ or Tolomeo).

If you have made it so far, thanks for reading! Let me know if you have any questions about any of these lamps.

The Daily Front Page 14 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — The Price of Public Records
article

Texas city demands $2M for public records on Flock usage

by 01-_-·▲ 147 points·25 comments·arstechnica.com ↗
Prices of public records tracking cops’ use of Flock go up as backlash swells.

Prices of public records tracking cops’ use of Flock go up as backlash swells.

Flock Safety camera

Credit: Justin Sullivan / Staff | Getty Images News

As bipartisan backlash against Flock grows, some cities are asking anti-surveillance advocates and media outlets to pay eye-popping fees—including charging tens of thousands or even millions—to get information about how police departments are using and potentially abusing AI-enabled camera systems that track every vehicle that passes them.

On Monday, the Texas Tribune reported that city officials in a Fort Worth suburb, North Richland Hills, asked one group to pay $2.3 million before it would fulfill a public records request for Flock data. To reach that high fee, officials claimed that searching “about a terabyte worth of communications about errors, misuse, and effectiveness of the Flock system” would take approximately 14 years of labor at a rate of $15 per hour.

Phil Mynona, who filed the request using a pseudonym on behalf of his group, the Texas Privacy Coalition, told the Tribune that the fee seemed “ludicrous” and designed to stifle his public records searches.

Mynona has sought similar records from more than 200 law enforcement agencies across the US, and he said it was impossible to predict how cities assessed fees for Flock records. Some cities provided more than 400,000 pages of documents for free, while others charged $5,000. Other groups, including a Houston news station called KPRC, have seen officials quote up to $121,000 for Flock records, the Tribune reported.

The high price tags may be hiding data that anti-surveillance groups note have triggered audits, arrests, and changes in how law enforcement uses cameras, including decisions to get rid of cameras. Many cops have been found using the cameras to stalk strangers and people in their personal lives, and so far, Flock has yet to introduce meaningful reforms to confront its stalker cop problem.

Texas is a perfect example of how increasing transparency about police use of Flock cameras works to protect the public from invasive searches that serve no lawful purpose. Last week, an ex-Texas cop, Zachary Anthony Klein, reportedly pled guilty to 100 felony counts of misuse of official information, which he agreed to do in exchange for the state not pursuing charges related to stalking several people. Klein’s Flock abuse—along with another cop’s—was outed after USA Today submitted a public records request that sparked a probe, then his arrest. Disturbed by the case, Texas Governor Greg Abbott quickly halted Flock funding and stopped issuing permits, the Tribune noted.

Additionally concerning are officials who deny requests outright. Consider that the Tribune reported that the state Department of Public Safety has sought help from “the Attorney General’s Office to allow it to withhold the entirety” of Flock data that the Texas Tribune has requested. And that denial came after DPS had already responded to an identical request seeking data from prior weeks, the Tribune noted.

Flock misuse recently ruled unconstitutional

Flock maintains that its automated license plate readers (ALPR) are designed for public safety, while courts have largely agreed that cops can reasonably access Flock databases without infringing Fourth Amendment rights. But ongoingly, there are cases dominating the headlines that show a widening web of privacy risks, including not just illegal surveillance by police but also hackers or bad actors improperly accessing data that can be used to track people’s daily movements.

Courts may start to rethink their stance on Flock, with one federal judge in Oklahoma last week ruling that a cop conducted an unconstitutional search when searching a Flock database simply because a woman’s license plate was from California,” 404 Media reported.

That judge, Sara Hill, argued that Flock’s network “is a type of indiscriminate mass surveillance,” with its ALPR technology creating a “large-scale, dragnet-type surveillance system” that should require a warrant to search.

A Flock spokesperson told 404 Media that the company had nothing to do with the case but expects Hill’s ruling to be an outlier that will likely be appealed and overturned.

Importantly, Hill’s decision does not set any precedent, but it could be influential as one of the first to recognize that Flock searches can be unconstitutional. 404 Media said they reviewed audits showing “there are currently more than a hundred thousand warrantless searches of the Flock system every month.” Sometimes innocent people are arrested, including one man jailed for a month based on a Flock alert that he argued should have itself provided the evidence cops needed to see that he was innocent and five miles away from the crime scene.

For members of the public increasingly scrutinizing Flock cameras over unconstitutional searches and other privacy concerns, it’s hard to know basic things, like where the cameras are posted, who’s looking at the footage, how often the data is accessed, and how long the data is stored.

Public records requests can help answer these questions, and sometimes police choose to voluntarily share it, using optional “transparency portals” that Flock builds. Those portals log statistics like total number of cameras, vehicles scanned, or police searches in a given area.

Flock spokesperson Andrew Smith told the Texas Tribune that the portals “give agencies a public-facing way to publish information about their [ALPR] programs, including policies, usage, and access rules to help communities better understand how the technology is being used.”

However, very few agencies seem to be opting in to the sharing. In Texas, there are hundreds of agencies using Flock cameras, and only 59 agencies use transparency portals, the Tribune reported. Of those, just 16 share data with the public.

Without courts requiring warrants or state and local officials requiring more transparency, Flock cameras will continue tracking movements in ways that the public doesn’t fully understand, advocates warn. And new privacy risks may emerge as AI makes it easier to process data across the ever-broadening network.

Michael Soyfer is a lawyer at the Institute for Justice who “has studied Flock camera abuse and is litigating several cases on Fourth Amendment grounds,” 404 Media noted. He suggested that without more transparency on how police are using the cameras, Flock may end up building tools to support some of these police misuses the public dislikes, such as automating the type of alerts used when tracking vehicle movements that have raised false suspicions or caused wrongful arrests.

“We’re seeing that repeatedly with police flagging whatever they’ll call suspicious patterns of movement. Federal agents were using ALPRs to monitor cars making day trips across the border and back to manufacture a basis to stop them, interrogate the drivers, and search them,” Soyfer told 404 Media. “I think Flock is going to automate that, using AI where cops can set alerts for those kinds of travel patterns.”

The Daily Front Page 15 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — A GTK Todo, in Haskell
article

Making a GTK application in Haskell, part 1

by Vosporos·▲ 144 points·37 comments·floreal.tech ↗
In this series, we are going to build a todo-list application using Haskell, GTK 4, and the Adwaita library.

In this series, we are going to build a todo-list application using Haskell, GTK 4, and the Adwaita library. Adwaita will provide us with many useful widgets and styles. Let's dive in!

This series' intended audience is intermediate Haskellers, with development experience with the language.

GTK 4, Adwaita

Adwaita is a library of GTK components that serve as the design language of the GNOME project. In short: Every decision that the GNOME project has made in terms of accessibility and style (the Human Interface Guidelines, HIG) is encoded in libadwaita.

Libawaita gives you many features: for instance it lets you create applications with responsive design, which are recolored at runtime when the desktop switches between light and dark themes.

Haskell and GTK

Throughout this series we will use the haskell-gi toolkit, which auto-generates Haskell bindings from GTK libraries, and allows us to get a Haskell interface to GTK that you can still relate to the C API.


To keep this post readable, the code that you will see will not be complete, in order for me to underline the main concepts.
You can find the whole project at https://github.com/Floreal-Technologies/adwaita-todo.


Your first window

To begin, here is a self-contained example of the structure of a GTK 4 / Adwaita application.

Let's create the adwaita "Application" that will handle resource management for us (including Adwaita stylesheets, which are pretty cool):

module Main (main) where

import GI.Adw qualified as Adw
import GI.Gio qualified as Gio
import GI.GTK qualified as Gtk

main :: IO ()
main = do
  -- The `new X [#attribute := value]` syntax creates a Gtk object
  -- with its properties. The hash syntax is called OverloadedLabels.
  app <- new Adw.Application [#applicationId := "tech.floreal.TodoApp"]
  -- We connect the "activate" signal to the "activate" handler.
  on app #activate (activate app)
  -- We run the main application loop.
  Gio.applicationRun app Nothing
  pure ()

activate :: Adw.Application -> IO ()
activate app = do
  header <- new Adw.HeaderBar []
  toolbar <- new Adw.ToolbarView []
  Adw.toolbarViewAddTopBar toolbar header
  window <- 
    new Adw.ApplicationWindow
      [ #application := app
      , #title := "Todos"
      , #defaultWidth := 480
      , #defaultHeight := 640
      , #content := toolbar
      ]
  Gtk.windowPresent window

Lo and behold! An empty window that displays "Todos" as its title, and its dimensions are 480 by 640.

An empty window

Model-View-Update: The Elm Architecture

The Elm Architecture (or TEA) is a pattern for architecting interactive programs. At its core are three concepts:

Model

The state of the application

View

The way to turn the Model into a user interface (HTML, GTK, etc)

Update

The way to update your Model based on Messages

Alongside those concepts we can find

Message

An enumeration of all the possible interactions of the user with the application

Effects

Not only does the Update function return an updated Model, but it returns also a list of actions to be performed on the side, called Effects.

This approach was broadly popularised by Elm, and lends itself quite well to taming the imperative nature of the GTK toolkit.

The Todo App

Now the time has come to represent our application state and its actions. In the spirit of the Elm Architecture, everything will be modelled as data structures, so that we have absolute visibility on what actions were triggered and what they entail.

The model

newtype TodoId = TodoId Word
  deriving stock (Show)
  deriving newtype (Eq, Ord)

data Todo = Todo
  { id :: TodoId
  , title :: Text
  , done :: Bool
  }
  deriving stock (Eq, Show)

data Model = Model
  { todos :: Map TodoId Todo
  , nextId :: TodoId 
  }
  deriving stock (Eq, Show)

-- In our case, the effect here represents
-- saving the todo-list on disk.
data Effect = Save [Todo]
  deriving stock (Eq, Show)

init :: Model
init = Model
  { todos = Map.empty
  , nextId = TodoId 0
  }

The messages

User interactions with the application are modelled as Messages: A known set of actions for which we have clear actions that modify the model.

Let's start with a couple of messages that the user may trigger to update the model:

data Message
  = Add Text
  | SetDoneStatus TodoId Bool
deriving stock (Eq, Ord)

Not much so far, but we will add more as we go.

Updating the model

update :: Message -> Model -> (Model, [Effect])
update message model = case message of
  Add raw -> 
    let text = Text.strip raw
        todoId@(TodoId n) = model.nextId
        todo = Todo{ id = todoId, title = text, done = False }
    in if Text.null text
    then (model, [])
    else
      withTodos
        (Map.insert todo.id todo)
        model{ nextId = TodoId (n + 1)}
  SetDoneStatus todoId value ->
    withTodos (Map.adjust (\todo -> todo {done = value}) todoId) model
 where
  -- This is where we determine if our todos have changed,
  -- so that we can save them.
  withTodos f changed =
    let result = changed {todos = f changed.todos}
    in if result.todos == model.todos
         then (result, [])
         else (result, [Save (Map.elems result.todos)])

Let's now open GHCi and try things out:

$ cabal repl
-- Let's add a task to buy leeks
ghci> let (m1, e1) = update (Add "Buy leeks") init

-- This triggers a "Save" effect for an unfinished task
ghci> e1
[Save [Todo {id = TodoId 0, title = "Buy leeks", done = False}]]

-- Let's set the task as done
ghci> let (m2, e2) = update (SetDoneStatus (TodoId 0) True) m1

-- Since the status has changed, we have to save it
ghci> e2
[Save [Todo {id = TodoId 0, title = "Buy leeks", done = True}]]

-- Setting the task to True again does not trigger a Save effect,
-- so the effects list is empty.
ghci> update (SetDoneStatus (TodoId 0) True) m2
(Model{ nextId = TodoId 1
      , todos = fromList [
          (TodoId 0, Todo{ id = TodoId 0
                         , title = "Buy leeks"
                         , done = True})]
      }, []) -- ← empty list!

This is our domain logic, encoded as a sum type of messages and an update function to change the state.

Let us now design our interface.

The View

It's always good to write down what your expectations are before starting a user interface.

From experience, design does not immediately follow from data, and so I tend less and less to look at the shape of my data to inform my designs.

Draft of the UI on a piece of paper

In our case it is pretty simple, but I like to draw.

Widgets

We are going to make use of several widgets (Click on their name to see a screenshot of what they look like):

Box

A box arranges child widgets in a row or column

ListBox

A list of rows that can be dynamically filtered and sorted. Useful later to filter on status and sort by age.

EntryRow

The entry of a row, with a title, a placeholder text, and an icon to show that it is editable. It is a sublass of ListBox, so it will live in a ListBox.

ActionRow

A more restricted version of the EntryRow, which cannot be edited in-place. It can still get action icons, and lives in a ListBox.

Clamp

A widget that constrains its child to a given size. Useful to enforce margins so that the background is visible at the edges.

ScrolledWindow

This widget makes its child scrollable. Does what it says on the tin.

ToolbarView

A view widget containing a page, as well as top and bottom bars.

Time 2 Lego

With those building blocks at hand, let's write down how our widgets connect with each other:

module Todo.View (view) where

-- Imports
-- […]

-- `dispatch` will be defined later in the Runtime module,
-- and is the function that  turns a message into a change
-- of state / model.
view
  :: (Message -> IO ())
  -> Model
  -> IO Gtk.Widget
view dispatch model = do
  -- Here, we define our input row, with its title and a signal handler
  -- to activate the retrieval of our input when it is activated.
  inputRow <- new Adw.EntryRow [#title := "New task"]
  on entry #entryActivated $ do
    text <- Gtk.editableGetText inputRow
    dispatch (Add text) -- This is where we send our "Add" message

  -- EntryRow is a subclass of ListBox,
  -- so we must append our inputRow inside entryBox
  entryBox <- newBoxedList 
  Gtk.listBoxAppend entryBox inputRow

  -- The ListBox that will contain our tasks
  todoList <- newBoxedList
  forM_ (model.todos) $ \todo -> do
    row <- new Adw.ActionRow [#title := todo.title, #useMarkup := False]
    Gtk.listBoxAppend todoList row

  -- The main content widget, with various options
  -- to define the margins within its parent
  -- as well as the orientation.
  content <-
    new
      Gtk.Box
      [ #orientation := Gtk.OrientationVertical
      , #spacing := 12
      , #marginTop := 12
      , #marginBottom := 12
      , #marginStart := 12
      , #marginEnd := 12
      ]
  -- Let's not forget to append everything…
  Gtk.boxAppend content entryBox
  Gtk.boxAppend content todoList

  -- The parents of the content widget.
  clamp <- new Adw.Clamp [#child := content]
  scrolled <-
    new
      Gtk.ScrolledWindow
      [ #child := clamp
      ]

  -- A cute little footer for additional information,
  -- like the amount of tasks.
  count <- new Gtk.Label [#label := Text.show (Map.size model.todos)]
  footer <-
    new
      Gtk.Box
      [ #orientation := Gtk.OrientationHorizontal
      , #marginTop := 6
      , #marginBottom := 6
      , #marginStart := 12
      , #marginEnd := 12
      ]
  Gtk.boxAppend footer count

  -- Now let's assemble the header, content and footer!
  header <- new Adw.HeaderBar []
  toolbar <- new Adw.ToolbarView [#content := scrolled]
  Adw.toolbarViewAddTopBar toolbar header
  Adw.toolbarViewAddBottomBar toolbar footer
  Gtk.toWidget toolbar

-- A little helper to create a ListBox with the correct settings.
newBoxedList :: IO Gtk.ListBox
newBoxedList =
  new
    Gtk.ListBox
    [ #selectionMode := Gtk.SelectionModeNone
    , #cssClasses := ["boxed-list"]
    ]

We can't get a lot of visual feedback yet, so you will have to trust that it resembles the pencil-and-paper draft from earlier.

The Runtime

Similarly to the content of the demo from the beginning of the article, this is where we plug the Model-View-Update trio.

We will define two more functions: dispatch and step, and they love each other very much.

dispatch takes a message, handles GTK execution loop priority, and calls step to perform the model update that will lead to the view update.

step reads the model, calls update (from Model.hs) on it to get the new model, write the new model, and pass the new model and the dispatch function to the View. The View gives back the new content as a Gtk widget, and we set this new content in the window.

Here is the code:

run :: Adw.Application -> IO ()
run app = do
  window <-
    new
      Adw.ApplicationWindow
      [ #application := app
      , #title := "Todos"
      , #defaultWidth := 480
      , #defaultHeight := 640
      ]
  ref <- newIORef Model.init
  let {- rec -}
      dispatch :: Model.Message -> IO ()
      dispatch message =
        void $ GLib.idleAdd GLib.PRIORITY_DEFAULT $ do
          step message
          pure GLib.SOURCE_REMOVE

      step :: Model.Message -> IO ()
      step message = do
        oldModel <- readIORef ref
        let (newModel, _effects) = Model.update message oldModel
        writeIORef ref newModel
        content <- View.view dispatch newModel
        Adw.applicationWindowSetContent window (Just content)

  content <- View.view dispatch Model.init
  Adw.applicationWindowSetContent window (Just content)
  Gtk.windowPresent window

Now, our Main module looks like this:

module Main where

main :: IO ()
main = do
  app <- new Adw.Application
     [#applicationId := "tech.floreal.AdwaitaTodo"]
  on app #activate (Runtime.run app)
  Gio.applicationRun app Nothing
  pure ()

And heeeere we go:

An application window with an input entry, and a list of two items 'Touch grass' and 'Buy leeks'

Pretty rad.


This concludes this article. See you in Part 2 for more features for our Todo List application!

The Daily Front Page 16 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Dust Without Gradients
article

Dust: Pretraining Transformers Without Backpropagation

by E-Reverance·▲ 139 points·30 comments·qlabs.sh ↗
We present the first zeroth-order method that is competitive with backprop at pretraining transformer language models.

Animation of the method

TL;DR

  • We present the first zeroth-order method that is competitive with backprop at pretraining transformer language models. Dust perturbs activations (node perturbation) independently at every token, so each token is a virtual population member and one forward pass evaluates them all in parallel.
  • Dust approximates backprop closely at large population (i.e. substantially more compute) and in multiple settings even exceeds it. This hints that in a compute-rich regime we might be able to surpass backprop.
  • Dust is orders of magnitude more efficient than weight-space ES. From 1M tokens up, Dust is on the order of $10^3$ to $10^4$ times more efficient than a transformer implementation of EGGROLL, a state-of-the-art ES method, based on our extrapolations.
  • Zeroth-order methods are widely believed not to scale to large networks. Strikingly, we find larger models are more population-efficient, not less: a 243M-parameter model outperforms a $120\times$ smaller model at most population sizes.
  • Dust’s gradient estimates align better with backprop’s as population grows, and stay well aligned at every scale we test, up to 1B tokens, which is encouraging for scaling.

1 Introduction

Deep learning has been built around backprop, the only credit assignment algorithm capable of training modern neural nets, including transformer-based language models. Backprop requires differentiability and produces first-order gradients, and deep learning’s architectures, optimizers, and hardware have co-evolved around this constraint.

However, as the amount of compute available in the world increases, we might prefer more generic and brute-force learning algorithms based on search over inductive biases like differentiability, backprop, and approximations of higher-order gradients. The bitter lesson (Sutton, 2019 Richard S. Sutton. The bitter lesson. http://www.incompleteideas.net/IncIdeas/BitterLesson.html, 2019. Blog post.) is that general methods that scale with compute eventually win, and AlphaGo Zero (Silver et al., 2017 David Silver, Julian Schrittwieser, Karen Simonyan, Ioannis Antonoglou, Aja Huang, Arthur Guez, Thomas Hubert, Lucas Baker, Matthew Lai, Adrian Bolton, Yutian Chen, Timothy Lillicrap, Fan Hui, Laurent Sifre, George van den Driessche, Thore Graepel, and Demis Hassabis. Mastering the game of Go without human knowledge. Nature, 550 (7676): 354–359, 2017. doi: 10.1038/nature24270.) is the obvious example. Bootstrapping AlphaGo on human data helped the network learn faster initially, but with a lot of computation the purely self-play network overtook it. Similarly, differentiability and backprop might be good inductive biases in the low-compute regime, where they make learning efficient, but in the high-compute regime they limit the space of architectures that work. Even within an architecture, gradient-based methods fail to explore the loss landscape optimally (Liu et al., 2020 Shengchao Liu, Dimitris Papailiopoulos, and Dimitris Achlioptas. Bad global minima exist and SGD can reach them. In Advances in Neural Information Processing Systems, volume 33, 2020.). This might also explain why current neural nets require massive amounts of data to generalize. A more flexible credit assignment algorithm based on search is likely an important step towards much better generalization.

In this paper, we aim to replace backprop with a learning algorithm based much more on brute-force computation and much less on analytic structure. We call it Dust. Dust is a zeroth-order optimization algorithm that perturbs activations, rewards each perturbation by how much it lowers the loss, and averages the reward-weighted perturbations over a population to estimate the gradient. Traditional ES methods that perturb weights (Salimans et al., 2017 Tim Salimans, Jonathan Ho, Xi Chen, Szymon Sidor, and Ilya Sutskever. Evolution strategies as a scalable alternative to reinforcement learning. arXiv preprint arXiv:1703.03864, 2017.), like EGGROLL (Sarkar et al., 2025 Bidipta Sarkar, Mattie Fellows, Juan Agustin Duque, Alistair Letcher, Antonio León Villares, Anya Sims, Clarisse Wibault, Dmitry Samsonov, Dylan Cope, Jarek Liesen, Kang Li, Lukas Seier, Theo Wolf, Uljad Berdica, Valentin Mohl, Alexander David Goldie, Aaron Courville, Karin Sevegnani, Shimon Whiteson, and Jakob Nicolaus Foerster. Evolution strategies at the hyperscale. arXiv preprint arXiv:2511.16652, 2025.), scale with population, but scaling the population is costly because each member must be materialized and evaluated. We remove both costs with the concept of virtual population, where we avoid materializing every member by bypassing weight space entirely and instead perturb activations, as in node perturbation (Werfel et al., 2003 Justin Werfel, Xiaohui Xie, and H. Sebastian Seung. Learning curves for stochastic gradient descent in linear feedforward networks. In Advances in Neural Information Processing Systems, volume 16, 2003.; Widrow and Lehr, 1990 Bernard Widrow and Michael A. Lehr. 30 years of adaptive neural networks: Perceptron, Madaline, and backpropagation. Proceedings of the IEEE, 78 (9): 1415–1442, 1990. doi: 10.1109/5.58323.). We do so independently at every token, so each token is a member and one forward pass evaluates them all in parallel.

Activations are a more interesting space to search over than weights. Mechanistic interpretability has shown that reasoning, whether verbalizable or not, lives in the activations (Gurnee et al., 2026 Wes Gurnee, Nicholas Sofroniew, Adam Pearce, Mateusz Piotrowski, Isaac Kauvar, Runjin Chen, Anna Soligo, Paul Bogdan, Euan Ong, Rowan Wang, Ben Thompson, David Abrahams, Subhash Kantamneni, Emmanuel Ameisen, Joshua Batson, and Jack Lindsey. Verbalizable representations form a global workspace in language models. arXiv preprint arXiv:2607.15495, 2026.; Lindsey et al., 2025 Jack Lindsey, Wes Gurnee, Emmanuel Ameisen, Brian Chen, Adam Pearce, Nicholas L. Turner, Craig Citro, et al. On the biology of a large language model. Transformer Circuits Thread, 2025.), which means this approach could turn training into a search over latent reasoning (Vegesna and Dahal, 2025 Akshay Vegesna and Samip Dahal. Decoupling search and learning in neural net training. arXiv preprint arXiv:2509.10973, 2025.). We then pair the activation-space perturbation with a very generic credit assignment rule that assigns different token-level rewards to different layer types in a transformer block. Those two biases, along with a few implementation details and efficiency measures, like avoiding interference between perturbed modules, are the whole algorithm.

We make the following contributions.

  • We present the first zeroth-order method that is competitive with backprop at pretraining transformer language models. At large populations Dust exceeds backprop in multiple settings, which suggests that in a compute-rich regime we might be able to surpass backprop.
  • Dust is orders of magnitude more efficient than weight-space ES. From 1M tokens up, Dust is on the order of $10^3$ to $10^4$ times more efficient than a transformer implementation of EGGROLL, based on our extrapolations.
  • Contrary to conventional wisdom, larger models are often more population-efficient, not less, and can make use of larger populations. This gives a new view of overparameterization as a larger search space with potentially better geometry.
  • Dust’s gradient estimates align better with backprop’s as the population grows, and the alignment holds up at every scale we test, up to 1B tokens, which is encouraging for scaling.

The goal of this paper is to lay the foundations of a search-based credit assignment algorithm that is competitive with backprop on the hardest task we could think of: pretraining transformers. We do not attempt to make it compute-efficient enough to replace backprop today. We also do not train the new kinds of neural nets it makes accessible, like nets with an external program in the loop or transformers looped over many steps that backpropagation through time struggles to train. Both are left to future work.

2 Method

Dust works as follows. We add Gaussian noise to the output of each linear layer, independently at every token, run a forward pass, and reward each token’s noise by the change in loss at that token. The reward-weighted noise, averaged over draws, is the estimated error at the layer’s output, and its outer product with the layer’s input is the weight gradient. Attention internals get a variant of it: they are credited through the estimated error at the attention output over current and future tokens, instead of the tokens’ loss directly. The core intuition is that while weight-space ES evaluates one population member per forward pass, we evaluate one per token, in parallel, and a member is materialized by adding noise to a hidden state, which is cheap. On a modern transformer a single forward pass therefore evaluates a population at least three orders of magnitude larger than weight-space ES. We describe each component in detail below.

2.1 Activation-Space Perturbation

The bottleneck of evolution strategies is population size. Every member needs its own perturbed copy of the weights and its own forward pass. EGGROLL (Sarkar et al., 2025 Bidipta Sarkar, Mattie Fellows, Juan Agustin Duque, Alistair Letcher, Antonio León Villares, Anya Sims, Clarisse Wibault, Dmitry Samsonov, Dylan Cope, Jarek Liesen, Kang Li, Lukas Seier, Theo Wolf, Uljad Berdica, Valentin Mohl, Alexander David Goldie, Aaron Courville, Karin Sevegnani, Shimon Whiteson, and Jakob Nicolaus Foerster. Evolution strategies at the hyperscale. arXiv preprint arXiv:2511.16652, 2025.) makes the copies cheap with low-rank perturbations, but each member is still one sequence element of the batch, so the population is bounded by the forward passes one can afford. We perturb activations instead, independently at every token. At that token the network behaves as if a low-rank perturbation had been applied to the weights of the layer that produced the activations, without the perturbation ever being materialized in the weights. We call this a virtual population. A sequence in a transformer has a few thousand tokens, so one forward pass evaluates a few thousand members per sequence instead of one. Every weight in the model is trained this way except the $2L$ residual mixing scalars, which are trained by ordinary weight-space ES.

Adding noise to activations rather than weights is node perturbation (Widrow and Lehr, 1990 Bernard Widrow and Michael A. Lehr. 30 years of adaptive neural networks: Perceptron, Madaline, and backpropagation. Proceedings of the IEEE, 78 (9): 1415–1442, 1990. doi: 10.1109/5.58323.), and the usual argument for it is dimensionality (Ren et al., 2023 Mengye Ren, Simon Kornblith, Renjie Liao, and Geoffrey Hinton. Scaling forward gradient with local losses. In International Conference on Learning Representations, 2023.; Werfel et al., 2003 Justin Werfel, Xiaohui Xie, and H. Sebastian Seung. Learning curves for stochastic gradient descent in linear feedforward networks. In Advances in Neural Information Processing Systems, volume 16, 2003.). A layer’s output has $d_{\mathrm{out}}$ entries and its weights have $d_{\mathrm{out}} \times d_{\mathrm{in}}$, so activation noise lives in a much smaller space. Naively, the dimensionality argument doesn’t hold for transformers with large activations across many tokens. The noise on one sequence is a $T \times d_{\mathrm{out}}$ tensor, which has at least as many entries as the weight matrix once $T \ge d_{\mathrm{in}}$. However, with per-token independent perturbations and rewards, what perturbing activations gives is a new, efficient population along the token axis that is orthogonal to the batch axis EGGROLL already relies on.

2.2 Credit Assignment

For a linear layer $y_t = W x_t$ we jitter its output at all tokens, $y_t \to y_t + \sigma a_t$ with $a_t \sim \mathcal{N}(0, I)$ and $\sigma$ the noise scale, and run the forward pass. At each token $s$ we calculate the centered loss reduction $c_s = \tilde{\ell}_s - \ell_s$, where $\ell_s$ is the perturbed loss and $\tilde{\ell}_s$ is the mean perturbed loss at that token across draws evaluated together in the same batched forward. The reward of the jitter at token $t$ is the loss reduction at $t$ and, with a decay $\gamma$, the loss reductions at the tokens after it, which the jitter also reaches through attention,

$$r_t = \sum_{s \ge t} \gamma^{\,s-t} c_s .$$

(1)

With $\gamma = 0$ a jitter is rewarded by its own token alone. We leave it to the tuning of Section 2.3 to decide which layers see the future tokens. One independent jitter of all tokens is a draw, and a population is $K$ draws. Averaged over the draws, the reward-weighted noise

$$\hat g_t = -\frac{1}{K\sigma}\sum_{i=1}^{K} r_t^{(i)} a_t^{(i)}$$

(2)

is the estimated error at the layer’s output, and its outer product with the layer’s input, which the forward pass already computed, summed over tokens, is the weight gradient,

$$\widehat{G}_W = \sum_t \hat g_t\, x_t^\top .$$

(3)

Backprop forms the same outer product with the same input. The only difference is that it gets the output error from the chain rule and we get it from the population. For an embedding layer $x_t$ is one-hot, so the outer product is a scatter-add of $\hat g_t$ into the token’s row.

With unlimited population the estimator above is the whole method, and every perturbation could go into one forward pass. Each draw’s reward-weighted noise is the gradient plus an error with no preferred direction. Over draws the gradient adds up linearly while the errors add up as the square root, so their ratio falls as the population grows and the interference vanishes in the limit.

2.3 Interference and Tuning

At a population we can afford, the main cost is interference, i.e. we jitter many layers at many tokens in the same forward pass, so the loss change that rewards one token’s noise also picks up the effect of every other perturbation in that pass. We reduce such interference in three ways. First, different layer types are jittered in separate forward passes, each with its own noise scale, and each block gets its own passes. These passes are cheaper than full forwards because the clean forward is cached and a draw for block $l$ only reruns blocks $l$ onward. Second, the attention internals (query, key, value, gate, value embedding) are jittered separately. Token losses barely register their jitters, so they are rewarded through the attention output instead, as described below. Third, the language modeling head is jittered directly on the cached logits, re-evaluating only the cross-entropy and only a slab of the vocabulary per draw, which costs a small fraction of a forward pass and lets the head run a much larger population.

For the attention internals we recompute only their block’s attention output with the jitter, from the cached clean activations. We score the jitters using the alignment with the estimated attention output gradients,

$$c_s = -\langle \hat g_s, \Delta o_s \rangle ,$$

(4)

where $\Delta o_s$ is the change the jitter makes in the attention output at token $s$ and $\hat g_s$ is that output’s estimated error from Equation 2. The reward is Equation 1 with these scores, computed per head, in place of the loss reductions.

The hyperparameters, the noise scale of each layer type, the credit decay of the attention internals and the share of the population each layer gets, can be tuned in two ways. One is a grid search that trains with each setting on a small token budget and keeps the setting that lowers the loss most. It is reliable but expensive. The other is a grid search that maximizes the cosine between our estimate and the backprop gradient on a single batch, which needs no training at all. A larger cosine on one batch doesn’t always lower the loss after training, so the cosine picks candidates and training decides. Either way the tuning is mostly a one-time cost, since the settings it finds largely generalize across token budgets and population sizes, with one exception. At the largest population at 10M and 20M tokens, a slower credit decay and a shift of draws toward the attention side still pay (Appendix F). Hence, this search recovers general principles of the method rather than settings for one run. As expected, all layers require no credits from future tokens except the keys, values, gates and value embeddings, which are read by the later tokens that attend to them and get a $\gamma$ close to one.

3 Pretraining Without a Backward Pass

3.1 Setup

We train GPT-style transformers on FineWeb with a 4096-token BPE tokenizer, a batch of 16k tokens (8 sequences of 2048 tokens), one epoch, and SGD with momentum at a constant learning rate. The base model has 8 layers and width 512. Every method gets the same protocol and three seeds per cell, and is tuned separately at every token budget and population. Dust and backprop share one momentum and learning-rate grid; we implement EGGROLL with the same transformer architecture (named EGGROLL-Transformer) and it is tuned over its own grid of step size, momentum, noise scale and fitness shaping. Validation and test are held-out sets of 544 sequences each. We report the test loss at best validation checkpoint.

We count population in draws for Dust and in forward passes of the batch for EGGROLL (Sarkar et al., 2025 Bidipta Sarkar, Mattie Fellows, Juan Agustin Duque, Alistair Letcher, Antonio León Villares, Anya Sims, Clarisse Wibault, Dmitry Samsonov, Dylan Cope, Jarek Liesen, Kang Li, Lukas Seier, Theo Wolf, Uljad Berdica, Valentin Mohl, Alexander David Goldie, Aaron Courville, Karin Sevegnani, Shimon Whiteson, and Jakob Nicolaus Foerster. Evolution strategies at the hyperscale. arXiv preprint arXiv:2511.16652, 2025.), our weight-space baseline. A draw is one jitter of activations across all tokens of selected layers, rewarded with the token losses, and the population $K$ is the number of draws per update. A draw is slightly cheaper than a forward pass, because the clean forward is cached and a draw that jitters block $l$ reruns only the blocks from $l$ on. $K$ leaves out the draws of the head and the attention internals, which are a small fraction of the update’s FLOPs (Appendix E). Taken together, from a population of 256 up Dust uses less compute than EGGROLL at the same population, so the comparison is lenient to EGGROLL.

3.2 Main Results

Figure 1: Validation loss over training at 1M and 10M tokens for Dust (violet), EGGROLL at the same populations (gray) and backprop (black, dashed). The x-axis is the fraction of the token budget consumed. Shade is population, 64, 1k and 16k, darker for larger. Curves are means over three seeds.

Figure 2: Test loss at the validation-selected checkpoint against population, one panel per token budget, for Dust (violet) and EGGROLL-Transformer (gray). Points are the cells of Table 1, the dotted black line is backprop tuned at the same budget, and the dashed curve is a power law fit through Dust’s five cells. The 100k panel has its own y range; the other three share one. At 20M the dash-dotted violet line is the fit’s limit, 4.43, an extrapolation from a ladder that is still falling, and the bar at $\infty$ is its 95% bootstrap interval, with the seeds resampled at each population.

We sweep the token budget from 100k to 20M against populations from 64 to 16k, with backprop tuned on the same grid at every budget (Table 1, Figure 2). At 100k and 1M tokens Dust ends below backprop, from a few hundred draws at 100k and from a thousand at 1M. At 10M and 20M tokens, the gap with backprop shrinks with population. At 10M the ladder has flattened and its fitted limit lands just above backprop. At 20M the ladder is still falling at 16k draws. Its power law fit puts the limit at 4.431 (95% interval 3.89 to 4.58), below backprop’s 4.633, but with the ladder still falling the fit is loosely constrained, so we read it as evidence that the gap keeps closing with population rather than as a measured limit.

Weight-space ES is far less efficient. With 256 times the population, EGGROLL at 16k still does not reach Dust at 64 draws. It comes within 0.02 at 100k tokens and stays 0.4 to 0.6 above at 1M, 10M and 20M (Figure 2). EGGROLL’s ladder is still falling steeply at 16k, so it would keep improving with more population, but continuing the ladder puts what it needs to match Dust’s smallest population at several thousand to about $10^4$ times that population (Appendix D). Figure 1 also shows the gap during training; Dust at 1k and 16k draws stays close to backprop’s curve throughout, while every EGGROLL curve falls behind early and flattens well above Dust at 64 draws.

3.3 Dust Under Adam

Figure 3: Test loss against population at 1M tokens with Adam, for Dust (violet), EGGROLL (gray) and backprop (black, dotted). The violet curve is a power law fit in population over the populations run, and the dash-dotted violet line is its limit, 5.248, below backprop. The bar at $\infty$ is the limit’s 95% bootstrap interval, 5.17 to 5.30, with the seeds resampled at each population. Means over five seeds for Dust and backprop and three for EGGROLL; the Adam runs of Dust give the token embedding more draws, about $1.4\times$ the listed population in total.

While we focus primarily on SGD for the rest of the paper, we repeat the 1M token ladder with Adam on all three methods (Figure 3), re-tuning backprop’s learning rates, Dust’s own hyperparameters and EGGROLL’s step size, momentum and fitness shaping at every population. Interestingly, EGGROLL gains almost nothing from Adam and its tuned Adam ladder lands within 0.01 of its SGD ladder in Table 1 at every population. However, Adam improves both Dust and backprop and leaves the ladder’s shape similar to before. Dust closes on backprop with a large population and the interval on its limit sits below backprop (Figure 3). So Dust’s estimate already works with modern optimizers, even though modern optimizers were optimized for backprop gradients. We suspect that coevolution of optimizers with Dust could lead to further gains and leave this to future work.

4 Search in High-Dimensional Space

4.1 Overparameterization

Figure 4: Four model sizes at a fixed 10M tokens, 2M to 243M parameters (L2/d128, L4/d256, L8/d512, L16/d1024), test loss against population. The table has the same cells and backprop per size, with the best size at each population in bold.

The conventional view is that zeroth-order methods cannot train large networks (Lillicrap et al., 2020 Timothy P. Lillicrap, Adam Santoro, Luke Marris, Colin J. Akerman, and Geoffrey Hinton. Backpropagation and the brain. Nature Reviews Neuroscience, 21 (6): 335–346, 2020. doi: 10.1038/s41583-020-0277-3.). A forward pass returns a single scalar, so the variance of the gradient estimate grows with the number of perturbed dimensions, and with it the population needed for a useful update (Nesterov and Spokoiny, 2017 Yurii Nesterov and Vladimir Spokoiny. Random gradient-free minimization of convex functions. Foundations of Computational Mathematics, 17 (2): 527–566, 2017. doi: 10.1007/s10208-015-9296-2.; Werfel et al., 2003 Justin Werfel, Xiaohui Xie, and H. Sebastian Seung. Learning curves for stochastic gradient descent in linear feedforward networks. In Advances in Neural Information Processing Systems, volume 16, 2003.). We test this directly by training four sizes, 2M, 7M, 38M and 243M parameters (a $120\times$ range in parameter count), at a fixed 10M tokens across the population sweep (Figure 4; see Appendix F for tuning details). We make two striking observations that challenge conventional wisdom.

  • Bigger models are often more population-efficient, not less. At every population from 256 up the loss falls from 2M to 7M to 38M parameters, and the 243M model is only slightly worse. Even at the smallest population we test, a model $120\times$ larger does about the same, and is better at every other population. Up to a point, a larger model gains more from its size than it loses to variance. What we observe, however, is that the gap to backprop at the same population and model size increases with model size, but barely noticeable, esp at large population sizes.
  • Bigger models keep improving with population where small ones flatten. Small models saturate sooner, while big models keep improving with large population sizes. Past 1k draws the 38M and 243M models gain about 30% more than the 2M and 7M ones, and no amount of population makes the tiny model competitive.

The right way to think about model size is therefore as the size and the geometry of the search space. A larger model has a larger space to search over, which is what lets it put a large population to use, and potentially a better-conditioned loss landscape geometry, which could be why the search is more effective even at small populations.

4.2 Emergence of Backprop-Like Gradients

Figure 5: Cosine between the estimated and the backprop gradient on the same batch, per layer type (mean over layers; MLP averages the input and output projections), against population, for Dust on backprop-trained checkpoints at 10M, 100M and 1B tokens and for EGGROLL at 10M tokens at the same compute budget (left, note the axis). For Dust the lines are the fitted law $\cos(K) = c_{\max}/\sqrt{1 + c/K}$ through measurements at populations of 64 to 128k; for EGGROLL they connect the measurements. The dotted vertical line is the 16k population the ladders train at. Initialization and EGGROLL at 100M tokens are in Appendix B.

We measure the cosine between Dust’s estimate and the backprop gradient on the same batch, per layer type and per layer, on backprop-trained checkpoints spanning two orders of magnitude in tokens, i.e. from 10M to 1B tokens, with the population growing from 64 to 128k forward passes per step (Figure 5). The cosine rises with population for every layer type at every stage of training, and a two-parameter law

$$\cos(K) = \frac{c_{\max}}{\sqrt{1 + c/K}}$$

(5)

fits each layer type with RMSE below 0.06, with $c_{\max}$ the ceiling and $c$ the population at which the layer reaches $c_{\max}/\sqrt{2}$. Useful gradients emerge from the large population alone, with nothing about the chain rule built in, just light tuning of the hyperparameters to maximize the cosine similarity as described in Section 2.3. For the 100M token checkpoint, the fits to layer type mean cosine similarities have RMSEs of $0.0032$–$0.0367$ (see Appendix G for details). Dust’s gradients approach backprop’s in cosine, but how close they get varies by layer type and by layer. EGGROLL’s estimate, measured the same way at the same number of forward passes, is growing with population but is still below 0.05 in cosine at 128k for every type but the head, which might explain why training on it went nowhere in Section 3.2.

Importantly, the cosines hold up across most layers as the token count grows, which is encouraging for scaling. Section 3 shows the population required to match and exceed backprop grows with tokens. However, the cosine stays flat across two orders of magnitude in tokens at large populations, which means that at a large enough population it’s possible that this requirement no longer grows with more tokens. Furthermore, the fact that Dust’s gradients approach backprop’s but don’t converge to them exactly is in fact a good property. The estimate points in a similar direction without being backprop’s gradient, which leads to a different optimization trajectory, and in our experiments that trajectory can even be better than backprop’s (Section 3.2).

5 Conclusion

Since Rumelhart et al. (1986) David E. Rumelhart, Geoffrey E. Hinton, and Ronald J. Williams. Learning representations by back-propagating errors. Nature, 323: 533–536, 1986., backprop has been the algorithm that trains neural nets, and the architectures, optimizers and hardware we have were all built around it. As compute becomes more abundant, we think much better alternatives are possible. We introduced Dust, an algorithm that drastically improves upon existing ES algorithms and approximates backprop closely at pretraining transformers, even exceeding it with large amounts of computation.

There are many interesting open questions. The first is whether, and how, Dust can find better directions than backprop’s first-order gradient by implicitly exploring the loss landscape, picking up higher-order curvature that pulls the search toward flat regions. We have hints that it can, since at large populations it sometimes ends up below backprop, but the mechanism is not clear. The second is that Dust opens up the search space over architectures, since it does not need the network to be end-to-end differentiable, and it may do better where backprop is known to struggle, like recurrent or looped computation trained by backpropagation through time. The third is compute efficiency, which was not the focus of this paper. We must have orders of magnitude more compute efficiency before Dust becomes a practical alternative to backprop at current levels of compute.

6 Related Work

Early work on zeroth-order pretraining of language models (Allaire et al., 2025 Nathan Allaire, Mahsa Ghazvini Nejad, Sébastien Le Digabel, and Vahid Partovi Nia. Zeroth order optimization for pretraining language models. In Proceedings of ICPRAM, pages 113–121, 2025. doi: 10.5220/0013261100003905. URL https://doi.org/10.5220/0013261100003905.) examined the difficulty of training transformers from scratch with weight perturbations. Their later method, KronZO (Allaire et al., 2026 Nathan Allaire, Sébastien Le Digabel, Dominique Orban, and Vahid Partovi Nia. Zeroth-order Kronecker optimization for pretraining language models. SN Computer Science, 7, 2026. URL https://www.gerad.ca/en/papers/G-2025-44. Article 162.), uses compact perturbations with Kronecker structure and selective directional updates to improve pretraining while reducing memory use. EGGROLL (Sarkar et al., 2025 Bidipta Sarkar, Mattie Fellows, Juan Agustin Duque, Alistair Letcher, Antonio León Villares, Anya Sims, Clarisse Wibault, Dmitry Samsonov, Dylan Cope, Jarek Liesen, Kang Li, Lukas Seier, Theo Wolf, Uljad Berdica, Valentin Mohl, Alexander David Goldie, Aaron Courville, Karin Sevegnani, Shimon Whiteson, and Jakob Nicolaus Foerster. Evolution strategies at the hyperscale. arXiv preprint arXiv:2511.16652, 2025.) makes large populations of weight perturbations efficient on GPUs through low-rank structure. Dust instead searches over activations and uses rewards for each token to extract more credit from each forward pass.

For fine tuning, MeZO (Malladi et al., 2023 Sadhika Malladi, Tianyu Gao, Eshaan Nichani, Alex Damian, Jason D. Lee, Danqi Chen, and Sanjeev Arora. Fine-tuning language models with just forward passes. In Advances in Neural Information Processing Systems, volume 36, 2023.) showed that language models can be adapted with forward passes alone and memory use close to inference. Evolution Strategies at Scale (Qiu et al., 2026 Xin Qiu, Yulu Gan, Conor F. Hayes, Qiyao Liang, Yinggan Xu, Roberto Dailey, Elliot Meyerson, Babak Hodjat, and Risto Miikkulainen. Evolution strategies at scale: LLM fine-tuning beyond reinforcement learning. In Proceedings of the International Conference on Machine Learning, 2026. URL https://arxiv.org/abs/2509.24372. arXiv:2509.24372.) demonstrates fine tuning of all parameters with ES in language models with billions of parameters. Neural Thickets (Gan and Isola, 2026 Yulu Gan and Phillip Isola. Neural thickets: Diverse task experts are dense around pretrained weights. arXiv preprint arXiv:2603.12228, 2026. URL https://arxiv.org/abs/2603.12228.) finds useful task experts by randomly perturbing pretrained weights, selecting the best candidates and ensembling their predictions. These results show how much search can achieve around a pretrained model. Our experiments address learning the representations themselves through pretraining from scratch.

Our activation perturbations build on node perturbation (Werfel et al., 2003 Justin Werfel, Xiaohui Xie, and H. Sebastian Seung. Learning curves for stochastic gradient descent in linear feedforward networks. In Advances in Neural Information Processing Systems, volume 16, 2003.). GEMINI (Le Cun et al., 1988 Yann Le Cun, Conrad C. Galland, and Geoffrey E. Hinton. GEMINI: Gradient estimation through matrix inversion after noise injection. In Advances in Neural Information Processing Systems, volume 1, pages 141–148, 1988. URL https://papers.neurips.cc/paper_files/paper/1988/file/a0a080f42e6f13b3a2df133f073095dd-Paper.pdf.) injected noise into the first hidden layer and recovered layerwise gradient estimates through iterative matrix inversion. Zoop (Hu et al., 2025 Xixi Hu, Bo Liu, Qiang Liu, Xiaocong Du, Bhargav Bhushanam, Louis Feng, Chengyue Gong, and Kaizhao Liang. Zoop it! Efficient zero-order optimization with output perturbation. In ICML Workshop on Tiny Titans: The next wave of On-Device Learning for Foundation Models, 2025. URL https://openreview.net/forum?id=Tc8vFyRhPO.) uses output perturbations for language model fine tuning, converting estimated output gradients into parameter updates with local derivatives. Scaling Forward Gradient with Local Losses (Ren et al., 2023 Mengye Ren, Simon Kornblith, Renjie Liao, and Geoffrey Hinton. Scaling forward gradient with local losses. In International Conference on Learning Representations, 2023.) combines activation perturbations and local losses with forward mode automatic differentiation to reduce estimator variance. Forward gradients with multiple tangents (Flügel et al., 2025 Katharina Flügel, Daniel Coquelin, Marie Weiel, Charlotte Debus, Achim Streit, and Markus Götz. Beyond backpropagation: Optimization with multi-tangent forward gradients. In International Joint Conference on Neural Networks, 2025. URL https://arxiv.org/pdf/2410.17764v2.) also use forward mode differentiation, combining multiple directional derivatives through orthogonal projection to improve gradient estimates.

A separate line of work replaces the global backward pass with local learning dynamics: Sakana AI’s PC-ALM (Seely and Gould, 2026 Jeffrey Seely and Julian Gould. Augmented Lagrangian predictive coding. arXiv preprint arXiv:2605.31022, 2026. URL https://arxiv.org/abs/2605.31022.) propagates credit through local predictive coding dynamics and Lagrange multipliers. It uses local derivatives and is evaluated on image classification tasks. Dust estimates credit from forward perturbations during transformer pretraining, combining rewards for each token with local targets for attention outputs.

References

Nathan Allaire, Mahsa Ghazvini Nejad, Sébastien Le Digabel, and Vahid Partovi Nia. Zeroth order optimization for pretraining language models. In Proceedings of ICPRAM, pages 113–121, 2025. doi: 10.5220/0013261100003905. URL https://doi.org/10.5220/0013261100003905.

Nathan Allaire, Sébastien Le Digabel, Dominique Orban, and Vahid Partovi Nia. Zeroth-order Kronecker optimization for pretraining language models. SN Computer Science, 7, 2026. URL https://www.gerad.ca/en/papers/G-2025-44. Article 162.

Katharina Flügel, Daniel Coquelin, Marie Weiel, Charlotte Debus, Achim Streit, and Markus Götz. Beyond backpropagation: Optimization with multi-tangent forward gradients. In International Joint Conference on Neural Networks, 2025. URL https://arxiv.org/pdf/2410.17764v2.

Yulu Gan and Phillip Isola. Neural thickets: Diverse task experts are dense around pretrained weights. arXiv preprint arXiv:2603.12228, 2026. URL https://arxiv.org/abs/2603.12228.

Wes Gurnee, Nicholas Sofroniew, Adam Pearce, Mateusz Piotrowski, Isaac Kauvar, Runjin Chen, Anna Soligo, Paul Bogdan, Euan Ong, Rowan Wang, Ben Thompson, David Abrahams, Subhash Kantamneni, Emmanuel Ameisen, Joshua Batson, and Jack Lindsey. Verbalizable representations form a global workspace in language models. arXiv preprint arXiv:2607.15495, 2026.

Xixi Hu, Bo Liu, Qiang Liu, Xiaocong Du, Bhargav Bhushanam, Louis Feng, Chengyue Gong, and Kaizhao Liang. Zoop it! Efficient zero-order optimization with output perturbation. In ICML Workshop on Tiny Titans: The next wave of On-Device Learning for Foundation Models, 2025. URL https://openreview.net/forum?id=Tc8vFyRhPO.

Yann Le Cun, Conrad C. Galland, and Geoffrey E. Hinton. GEMINI: Gradient estimation through matrix inversion after noise injection. In Advances in Neural Information Processing Systems, volume 1, pages 141–148, 1988. URL https://papers.neurips.cc/paper_files/paper/1988/file/a0a080f42e6f13b3a2df133f073095dd-Paper.pdf.

Timothy P. Lillicrap, Adam Santoro, Luke Marris, Colin J. Akerman, and Geoffrey Hinton. Backpropagation and the brain. Nature Reviews Neuroscience, 21 (6): 335–346, 2020. doi: 10.1038/s41583-020-0277-3.

Jack Lindsey, Wes Gurnee, Emmanuel Ameisen, Brian Chen, Adam Pearce, Nicholas L. Turner, Craig Citro, et al. On the biology of a large language model. Transformer Circuits Thread, 2025.

Shengchao Liu, Dimitris Papailiopoulos, and Dimitris Achlioptas. Bad global minima exist and SGD can reach them. In Advances in Neural Information Processing Systems, volume 33, 2020.

Sadhika Malladi, Tianyu Gao, Eshaan Nichani, Alex Damian, Jason D. Lee, Danqi Chen, and Sanjeev Arora. Fine-tuning language models with just forward passes. In Advances in Neural Information Processing Systems, volume 36, 2023.

Yurii Nesterov and Vladimir Spokoiny. Random gradient-free minimization of convex functions. Foundations of Computational Mathematics, 17 (2): 527–566, 2017. doi: 10.1007/s10208-015-9296-2.

Xin Qiu, Yulu Gan, Conor F. Hayes, Qiyao Liang, Yinggan Xu, Roberto Dailey, Elliot Meyerson, Babak Hodjat, and Risto Miikkulainen. Evolution strategies at scale: LLM fine-tuning beyond reinforcement learning. In Proceedings of the International Conference on Machine Learning, 2026. URL https://arxiv.org/abs/2509.24372. arXiv:2509.24372.

Mengye Ren, Simon Kornblith, Renjie Liao, and Geoffrey Hinton. Scaling forward gradient with local losses. In International Conference on Learning Representations, 2023.

David E. Rumelhart, Geoffrey E. Hinton, and Ronald J. Williams. Learning representations by back-propagating errors. Nature, 323: 533–536, 1986.

Tim Salimans, Jonathan Ho, Xi Chen, Szymon Sidor, and Ilya Sutskever. Evolution strategies as a scalable alternative to reinforcement learning. arXiv preprint arXiv:1703.03864, 2017.

Bidipta Sarkar, Mattie Fellows, Juan Agustin Duque, Alistair Letcher, Antonio León Villares, Anya Sims, Clarisse Wibault, Dmitry Samsonov, Dylan Cope, Jarek Liesen, Kang Li, Lukas Seier, Theo Wolf, Uljad Berdica, Valentin Mohl, Alexander David Goldie, Aaron Courville, Karin Sevegnani, Shimon Whiteson, and Jakob Nicolaus Foerster. Evolution strategies at the hyperscale. arXiv preprint arXiv:2511.16652, 2025.

Jeffrey Seely and Julian Gould. Augmented Lagrangian predictive coding. arXiv preprint arXiv:2605.31022, 2026. URL https://arxiv.org/abs/2605.31022.

David Silver, Julian Schrittwieser, Karen Simonyan, Ioannis Antonoglou, Aja Huang, Arthur Guez, Thomas Hubert, Lucas Baker, Matthew Lai, Adrian Bolton, Yutian Chen, Timothy Lillicrap, Fan Hui, Laurent Sifre, George van den Driessche, Thore Graepel, and Demis Hassabis. Mastering the game of Go without human knowledge. Nature, 550 (7676): 354–359, 2017. doi: 10.1038/nature24270.

Richard S. Sutton. The bitter lesson. http://www.incompleteideas.net/IncIdeas/BitterLesson.html, 2019. Blog post.

Akshay Vegesna and Samip Dahal. Decoupling search and learning in neural net training. arXiv preprint arXiv:2509.10973, 2025.

Justin Werfel, Xiaohui Xie, and H. Sebastian Seung. Learning curves for stochastic gradient descent in linear feedforward networks. In Advances in Neural Information Processing Systems, volume 16, 2003.

Bernard Widrow and Michael A. Lehr. 30 years of adaptive neural networks: Perceptron, Madaline, and backpropagation. Proceedings of the IEEE, 78 (9): 1415–1442, 1990. doi: 10.1109/5.58323.

The Daily Front Page 17 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Care Is Infrastructure
article

The future of independence is interdependence

by eustoria·▲ 136 points·103 comments·onlys.ky ↗
Every one of us depends on others; the only difference is how visible that dependence is.

Every one of us depends on others; the only difference is how visible that dependence is.

I spend most of my life in one room.

At first glance, that may not sound much like independence.

I cannot easily walk through my house. I need my husband’s help with some ordinary tasks. My daughter brings me things from the outside world. Groceries, medications, meals, and almost everything else arrive through the door. I use mobility equipment, delivery services, remote appointments, adaptive tools, and an improbable number of charging cables.

My room has been engineered around what my body can and cannot do.

There is an adjustable bed, a trapeze bar, a stability pole, shelves within reach, rolling carts, grabbers, remotes, and devices mounted to the wall. A small keyboard has a grip attached so I can hold it without dropping it. My tablet docks beside the bed. Bags hang from improvised hooks.

None of this happened all at once. The room evolved through years of trial and error, frustration, invention, and help from people who love me.

It would be easy to look at this arrangement and see dependence. But I look at it and see a functioning life.

From this room, I write articles, attend appointments, talk to friends, manage projects, edit essays, and take classes in graduate school. The assistance and technology surrounding me do not prevent independence. They make my version of it possible.

This only sounds contradictory because our culture has adopted a bizarre definition of independence: doing everything yourself, without visible assistance.

By that standard, almost no one is independent.

The myth of the self-sufficient person

We imagine a capable adult as someone who earns their own money, drives their own car, maintains their own home, and handles their own problems. This person may participate in society, but they are not supposed to need it too much.

Yet the supposedly self-sufficient person wakes in a home built by other people, turns on electricity delivered through a vast public infrastructure, drinks water transported through municipal pipes, eats food grown and shipped by strangers, and drives on roads they did not construct.

They rely on mechanics, doctors, pharmacists, sanitation workers, software developers, farmers, warehouse employees, electricians, and thousands of people they will never meet.

Increasingly, they also rely on algorithms. Phones provide directions. Calendar alerts remember appointments. Search engines retrieve information. Apps deliver food, transfer money, refill prescriptions, and summon transportation.

The difference between their dependence and mine is not that mine exists. It is that mine is visible.

Socially acceptable dependence

Our culture is selective about which kinds of assistance count as evidence of inadequacy. A person who drives to the grocery store is considered independent, although the car depends on fuel, roads, mechanics, insurance, and a global manufacturing network. A person who orders groceries because they cannot walk through the store may be considered dependent.

A wealthy person can outsource cooking, cleaning, transportation, scheduling, and shopping while remaining a model of success. A poor or disabled person who needs help with the same tasks may be expected to prove they have exhausted every other possibility.

The distinction is rarely about whether assistance is involved. It is about whose assistance has been normalized, purchased privately, concealed, or transformed into status.

Some people have the privilege of making their dependence invisible. Disabled people often do not. Our wheelchairs, canes, aides, ramps, medication organizers, and modified environments announce that human beings require support. This may make people uncomfortable because it undermines the fantasy that they do not.

Assistance versus agency

Part of the problem is that we confuse independence with autonomy. They're not the same thing.

Independence, as our culture usually defines it, means completing a task without help. Autonomy means having meaningful control over your own life. Sometimes that requires assistance.

I may need someone to bring an object across the room, but I still decide what I am doing with it. I may need my husband to drive me somewhere, but I still choose where I am going. I may rely on technology to work, but the thoughts and decisions remain mine.

A person can complete every physical task alone while having very little control over their life. Another can require extensive assistance while directing their care, maintaining relationships, creating work, and participating fully in the world.

Doing something without help is not the highest form of human functioning, but often, merely the least efficient. Disabled people learn this quickly because insisting on doing everything ourselves can consume an entire day’s energy, increase pain, create danger, or make the rest of life impossible.

I could use much of my limited strength trying to prove I do not need assistance. Or I could accept help and use that strength to write. I know which one produces a life I want.

Human survival has always been openly collective. People hunted, farmed, built, cooked, raised children, cared for the sick, and protected communities together. The fantasy of total self-sufficiency is not a description of human nature. It is a cultural story.

Disabled people understand this particularly well because we know that functioning is conditional. A person can be capable in one environment and unable to function in another.

A staircase can turn a mobile person into an immobile one. Captions can transform an inaccessible video into an accessible one. A flexible schedule can make employment possible. A delivery service can be the difference between having groceries and going without them.

Ability does not reside inside an individual body. It is created by the surrounding world.

The same principle applies beyond disability. Parents function differently when childcare is available. Workers function differently when they have paid leave. Older adults function differently when transportation and home assistance are available. Students function differently when they have reliable internet access.

The future can't afford the fantasy

The future will make our interdependence increasingly difficult to deny.

The world population is aging. More people will live with chronic illness, mobility limitations, cognitive changes, and the ordinary physical consequences of getting older. At the same time, families are smaller and more geographically dispersed. Many people will not have an adult child nearby who can absorb hours of unpaid care.

Meanwhile, healthcare, housing, transportation, and workplaces remain designed around an imaginary person who is healthy, mobile, cognitively consistent, technologically competent, and endlessly available.

We can continue treating every person who needs help as an individual crisis, forcing families to improvise private solutions until caregivers are exhausted and the people receiving care are isolated. Or we can admit that needing support is a predictable part of being human and design society accordingly.

That would mean accessible housing, reliable transportation, flexible employment, paid caregiving, affordable assistive technology, better home healthcare, and support that arrives before people reach a breaking point.

Climate instability will make the lesson unavoidable. Extreme heat, fires, floods, power outages, and disrupted supply chains reveal how thoroughly everyone depends on functioning roads, clean water, electricity, communication networks, pharmacies, emergency services, and neighbors willing to check on one another.

Resilience does not come from pretending everyone can survive alone. It comes from having strong networks of support.

Technology is also interdependence

Technology may allow more people to work, learn, communicate, receive healthcare, and remain at home longer. Smart devices can control lights, lock doors, provide reminders, call for help, and reduce the physical effort required for everyday tasks.

Artificial intelligence may help people organize information, navigate bureaucracy, translate language, and compensate for some cognitive or physical limitations. Robotics may eventually assist with lifting, mobility, household work, and personal care.

But technology will not eliminate dependence. It will create new forms of it.

A smart home depends on electricity, internet service, software, manufacturers, cybersecurity, technical support, and affordability. A robot caregiver will still require maintenance, oversight, funding, and ethical rules.

The better question is how technology can help people exercise greater autonomy within the relationships of dependence that already exist. It can also make care more sustainable instead of leaving every need to an exhausted spouse, daughter, friend, or neighbor.

Care is infrastructure

We usually speak of infrastructure as roads, bridges, power lines, water systems, and broadband. But care is a form of infrastructure too.

Without childcare, eldercare, healthcare, disability support, and domestic labor, the rest of society does not function. Yet care is largely absent from our dominant image of independence.

A person may appear self-sufficient because someone else schedules appointments, cooks meals, cleans the house, manages medications, or notices when something is wrong. That work is often underpaid, unpaid, or invisible.

Care is exhausting. A relationship of dependence can create unequal power. Families can be loving, willing to help, and still overwhelmed. People receiving assistance can be controlled, infantilized, neglected, or abused. That is precisely why care cannot remain invisible.

When we recognize it as essential infrastructure, we can build compensation, safeguards, alternatives, and accountability into it. We can protect both the autonomy of the person receiving care and the well-being of the person providing it.

What my room actually proves

A society designed for interdependence would not force people to become catastrophically ill before they qualified for support. It would not require disabled people to repeatedly prove incapacity in order to receive tools that increase their capacity.

It would recognize that accessibility benefits far more people than those carrying an official diagnosis. It would make remote participation ordinary, build homes people could continue living in as their bodies changed, and ensure that receiving care did not require surrendering dignity or control. It would also stop dividing people into helpers and helped, contributors and burdens.

I need help with many physical tasks. I also write, coach, organize, advise, make people laugh, and contribute to the lives of people around me. Support does not flow in only one direction. It moves through relationships in different forms at different times.

My life works because I stopped measuring success by how convincingly I could imitate a person who needed nothing. I accept help. I use tools. I rearrange the world within reach. I depend on people in some ways, and they depend on me in other ways.

The independent individual has always been imaginary, and disabled people already know this. Independence does not mean needing no one. It means having enough support to direct your own life.

The future of independence is not isolation.

It is interdependence, designed deliberately, rather than denied.

The Daily Front Page 18 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Example, Revised
article

Example.com just launched the biggest redesign in decades

by jgx0·▲ 131 points·78 comments·debugbear.com ↗
example.com is a reserved domain name set aside by the Internet Assigned Numbers Authority (IANA) for documentation purposes.

example.com is a reserved domain name set aside by the Internet Assigned Numbers Authority (IANA) for documentation purposes. It has been available as an example URL for developers and writers since the late nineties.

While the overall messaging of the page has been consistent over time, the visual appearance has received several major overhauls.

In this article, we take a look at the recent changes as well as the evolution of example.com over the last 20+ years.

What changed on 28 September 2026?

Until 28 September 2026, example.com was a static English-language page. The redesign introduces multi-language support using JavaScript, showing the content in a new language every 5 seconds.

Example.com shows an explanation of the site's purpose in English, Arabic, Chinese, French, Russian and Spanish. This is the English-language message:

This domain is for use in documentation examples without needing permission. This is not a service, avoid relying on it for testing and monitoring purposes.

Along with introducing multi-language support, the JavaScript code also inserts an SVG book icon.

How does the language transition animation work?

The new site doesn't just replace the content when showing the next language. Instead, there's a gradual opacity transition.

Language transition

The opacity animation itself just uses transition: opacity .4s;. But how is the character-by-character transition implemented?

Each character is wrapped in its own span element, and each span gets a slightly larger CSS transition-delay than the one before it. That means each character's opacity animation happens at a slightly different time.

Statement from IANA

IANA provided the following statement explaining the reasoning behind the recent changes:

The changes we make to the site from time-to-time are usually informed by a desire to either reduce the overall bandwidth demands of serving the site, or improve its utility. At its heart it is a placeholder for a site no-one should be accessing, but we have historically showed a message there to inform visitors about why the domain is registered and how they may use it.

As it tends to be heavily trafficked, the overall bandwidth is a key consideration, and to that end one of the changes we made this week was to split the page content into a more basic page, augmented by a separate Javascript file with additional content beyond that. Since most of the traffic to the site is automated it tends not to fetch the Javascript file, reducing overall data requirements.

The fundamental purpose of the domain is for use in documentation, such as illustrative examples you may find in instructions. We know that people may, for example, cut-and-paste a sample configuration file and forget to customize entries that contain an example domain, and we expect we get some incidental traffic from that. However, the domain isn't intended to be a general purpose endpoint for things like availability testing so we do not encourage that kind of usage. There is no requirement there is a HTTP service present on the host in order to fulfill its purpose, we just operate it as a courtesy.

January 20, 2002: What did the earliest version look like?

According to Wikipedia, the example.com website launched on January 1, 1999. The earliest version available to view in the Wayback Machine is from January 20, 2002.

The earliest version of the website only featured a list of domain names reserved by the Internet Corporation for Assigned Names and Numbers (ICANN) and IANA.

In the .com, .net, and .org top-level domains (TLDs), various domain names are reserved. These names are reserved from initial registration, but to the extent they are already registered the existing registrant may renew them.

Example.com: January 20, 2002

Structurally, the HTML used a table layout, with the ICANN logo positioned in the top left corner of the page.

The server headers show that the site used Apache 1.3.22 at this point.

March 28, 2002: simplified messaging

The first version of the example.com wording we recognize today came 67 days after the first available screenshot:

You have reached this web page by typing "example.com", "example.net", or "example.org" into your web browser.

These domain names are reserved for use in documentation and are not available for registration.

Example.com: March 28, 2002

February 7, 2003: RFC 2606 citation added

In February 2003, the content was amended to include a link to RFC 2606, the official document for reserved top-level and second-level domains, so visitors could find more information on the website's purpose.

There was also a small technical change around this time: the server was upgraded to Apache 1.3.27 on Red Hat Linux.

July 30, 2010: .edu added to domain list

The website then went unchanged for seven years. On July 30, 2010, a slight change was made: example.edu was now pointed to the landing page, alongside the three previous domains.

July 29, 2013: migration and landing page redesign

From January 2011, example.com didn't serve its own page. Instead, it redirected visitors to a page on IANA's website.

That changed on July 29, 2013, when the redirect was removed and example.com began serving its own page from the EdgeCast Content Delivery Network (CDN) instead of Apache, alongside a major redesign of the landing page. The new design used a rounded card with an <h1> reading 'Example Domain' and a new description of the website's purpose.

The viewable domain list was now gone, with a link to IANA's website for more information.

Example.com: July 29, 2013

October 17, 2019: font and copy changes

A new update came six years after the biggest change in the website's history. The layout remained the same, but the font stack was modernized to include more fallback fonts for devices such as Macs, iPhones, and Windows PCs.

The copy was tweaked slightly, with 'is for use in illustrative examples' replacing 'established to be used' and 'in literature' replacing 'in examples'.

Example.com: October 17, 2019

January 15, 2025: infrastructure switch

Almost twelve years after the switch from Apache to the EdgeCast CDN, another infrastructure change took place: the Server header disappeared entirely. The response headers alone don't reveal which platform was serving the page at this point.

A change of provider around this time isn't surprising. EdgeCast had been acquired from Yahoo by Limelight Networks in 2022 and rebranded as Edgio. Edgio then filed for Chapter 11 bankruptcy in late 2024, with Akamai acquiring select Edgio customer contracts.

October 9, 2025: redesign

Later in 2025, the page was redesigned. The card design was dropped, and the HTML was minified. The copy was changed to a more direct message, again linking to IANA's website, with the link text changed from 'More information...' to 'Learn more'.

Example.com: October 9, 2025

December 17, 2025: Cloudflare migration

Less than a year after the previous switch, the infrastructure changed again: the site now serves from Cloudflare, as indicated by the cloudflare server header and CF-RAY header in the response. Whatever platform served the page after the January 2025 change, it has now been replaced with a Cloudflare-fronted setup.

June 9, 2026: favicon and HTML tweaks

The next update, on June 9, 2026, brought no visual changes. The only HTML changes on the page itself were a favicon tag being added and the <p> tags being closed. The page now includes an empty favicon:



<link rel="icon" href="data:," />

This avoids a lot of unnecessary requests, as otherwise browsers look for a favicon at /favicon.ico.

Avoid relying on it for testing and monitoring purposes

Example.com first introduced an "Avoid use in operations" message in 2025.

For developers, it's tempting to use example.com to check if the network is working or test HTTP requests. The example server likely receives a lot of traffic through this.

However, as the page now clarifies, it's not a service you can rely on. When we look at our uptime monitoring data, we can see that every now and then the example.com server doesn't respond correctly.

Using infrastructure that your organization controls can be more reliable.

Example.com failed uptime checks

Conclusion

Looking at the visual timeline, we can see that changes to example.com happen sporadically. Sometimes a couple of small tweaks happen in back-to-back months. Other times the website remains untouched for periods of up to seven years.

We have been monitoring the page for several years in our public demo project. The Chrome UX Report (CrUX) data shows how page speed has changed over time.

Example.com performance data

The Daily Front Page 19 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Music Metadata, Major Release
article

Picard 3.0

by Tomte·▲ 129 points·46 comments·blog.metabrainz.org ↗
MusicBrainz Picard is the official tag editor for the MusicBrainz database.

The Picard team is happy to announce the new major version 3.0 of MusicBrainz Picard, now available to download. MusicBrainz Picard is the official tag editor for the MusicBrainz database and helps you get your music collection sorted and cleaned up with data from MusicBrainz.

An image of a mock software cardboard box, showing "MusicBrainz Picard" as the title. There are two worn-out looking stickers visible on the box, one saying "Complete Tagging Solution", one "Community Support". Beside the box there is a pink / orange circle with the text "Version 3".

This release brings many changes, including an upgrade to Qt6, a completely new plugin system, several improvements to the user interface, cover art processing, ISRC submission and many more. More details below.

What’s new?

User interface improvements

Qt is the application framework Picard is built upon. Qt simplifies the implementation of cross-platform desktop applications as it abstracts away many of the differences between various operating systems. Picard 2 was based on Qt5. With Picard 3 we have updated to Qt6. Besides ensuring that Picard stays up-to-date and available on modern desktops, this version change also brings some advantages like much improved support for screen scaling and better support for a dark mode. Specifically on Windows the old issues of having fonts scale inconsistently are now resolved. The UI now also supports a dark mode across all operating systems and switching between light and dark mode does no longer require a restart of the application.

Picard already supported customizing the file and album list views by selecting the columns to display. In previous versions this was limited to a couple of pre-defined columns, though. New contributor knguyen1 implemented full custom column support. You can now define your own columns, where you can define the actual column content using scripting. This gives a lot of flexibility showing exactly the information you need. There is also a new pre-defined “Match” column that allows to sort releases by match quality. For more details see the chapter Custom Columns in the documentation.

Screenshot showing the context menu for the main view column headers. The menu allows selecting columns and manage the columns. The entry "Manage custom columns" is highlighted.

The columns context menu, allowing you to customize the columns being shown in the main list views.

Another new feature, implemented by jpmsousa03, is the ability to filter the list views. You can select the fields to search and enter a search term. Only items matching this filter will be shown.

It is now possible to select and copy multiple tags in the metadata view and paste them on e.g. another tag, updating all corresponding tags. It is also possible to paste multiple copied values into a spreadsheet tool. This feature was provided by StevilKnevil.

The metadata view now also shows the actual differences between existing tags and the new tags being written.

On a first start Picard now shows a setup wizard, that guides new users through some essential configuration.

Screenshot of the Picard Setup Wizard dialog to configure File Organization. It allows toggling the options for "Rename files based on tags" and "Move files to a folder structure based on tags". Each option is shown with a more detailed expalantion.

Setup Wizard showing the File Organization settings.

Also some essential functionality, such as loading files and clustering, gets explained by a tutorial mode when a feature is first used. Both the wizard and tutorial can be disabled or re-enabled in the user interface options.

Screenshot of one of the tutorial pop-ups Picard shows when certain actions happen for the first time. In this case it shows the tutorial being shown when a release is loaded for the first time.

The tutorial being shown when a release is loaded for the first time.

New plugin system

Apart from the Qt6 migration the new plugin system is the most significant change in Picard 3. While the previous plugin system enabled a lot of flexibility in Picard, it has a couple of limitations. For example, Picard would load, and partially run, the code of each installed plugin on every start, whether the plugin was enabled or not. This could lead to unwanted side effects and unexpected behavior. On the development side it proved also difficult for third-party developers, especially for more complex plugins, as all code had to be checked into the central picard-plugins Git repository.

The new plugin system provides:

  • Separation of plugin metadata and code: MANIFEST.toml is mandatory
  • A defined plugin API with typing support
  • Git based versioning and updating of plugins
  • Plugins can be installed and updated from a central plugin registry, from third-party Git repositories, or from a local directory
  • Several trust levels (official, trusted, community, untrusted)
  • The ability to blacklist plugins centrally allows us to react on security issues
  • A picard-cli command line tool to manage (install, uninstall, update…) plugins
  • Plugins now support their own translation system (optionally manageable via Weblate), so their user interface texts can be translated
  • Plugins have their own configuration namespace

All the extension points known from Picard 2 to register metadata processors, context menu actions, cover art providers, file formats, option pages etc. are still available. But there are several new extension points; plugins can now register cover art filters and processors, custom variables, actions in a global “Plugin Tools” menu and CD ripping log file formats.

As a user, the new plugin management under Options → Plugins now clearly separates installed plugins from plugins available for installation. Both the list of installed and available plugins can be searched, and it is possible to install plugins from third-party developers. See the Plugins Options documentation for a more in-depth description.

Screenshot of the new Plugins options page, showing the list of currently installed plugins and a more detailed description of the selected one.

The new Plugins option page, showing a list of currently installed plugins.

This also means that Picard v2 plugins are not compatible and need to be migrated to the new system. There are already 30 plugins available, both plugins migrated from v2 and brand new ones. Have a look at the plugins v3 list on the Picard website.

If you are a developer and want to update your plugins to Picard 3 or maybe write a new one, please see the Plugin overview in the Picard User Guide and the detailed Picard Plugin v3 Documentation.

Cover art processing

It is now possible to both filter and process cover art loaded from cover art providers. The new options in Cover Art / Processing allow you to ignore images below a certain size or automatically resize loaded images or convert them to a specific file format. Cover art processing can be extended by Plugins, which can register their own cover art filters and processors. Filters can restrict what cover art gets loaded, while processors can perform image processing on the loaded cover art.

Cover art processing was implemented as part of Google Summer of Code 2024 by twodoorcoupe. You can read more about this in twodoorcoupe’s blog post GSoC 2024: Picard image processing.

New tags and scripting enhancements

As full support for synced lyrics was added, there is now a new %syncedlyrics% tag. The MuicBrainz Artist ID of a composer is available as a new tag %musicbrainz_composerid%.

There are also several new variables, that provide data for tagging and naming scripts, but are not written as tags to the files by default. The new %_genres% and %_folksonomy_tags% variables give you access to the raw list of genres or folksonomy tags as loaded from MusicBrainz. For recordings with a broadcasted relationship the broadcasting date is available as %_broadcast_date%. If a recording has a linked work with an ISWC, the ISWC is now available as %_iswc%.

The variables %_albumartists_countries% and %_artists_countries% contain all country codes for all credited album artists / track artists. Likewise the disambiguation comments for artists and album artists are available as %_artistcomment% and %_albumartistcomment%.

The %_filesize% variable contains the file size in bytes (if the script is running in a context where a file is available, i.e. on tracks with a matched file or in a file naming script).

There are now two new functions $get_new() and $get_original(), which allow to explicitly request the original or new value of a variable. The $rsearch scripting function gained a new optional parameter, which can be used to specify the capture group inside the regular expression to be returned. Please see the documentation of the $rsearch function for an example.

Improved built-in player

The built-in player received several improvements. As before the player is based on QtMultimedia. With Qt6 this component brings better cross-platform support for various audio formats and pitch-adjustment if playback speed changes (requires Qt 6.10).

The player has also been internally refactored to better separate the player and UI. This allows better integration with the OS. The player now supports macOS “Now Playing” and on Linux can be controlled by MPRIS2 compatible tools. It can also submit listens to ListenBrainz. Both OS integration and ListenBrainz support can be configured in the new Audio Player Options.

Save and restore user session

Picard can save and restore your current workspace state as a session file under the main File menu. Sessions preserve file placement (unclustered, clusters, albums, specific tracks, and standalone recordings), your manual metadata edits, and selected configuration options so you can resume work later. Thanks to knguyen1 for this feature. See the chapter Sessions Management in the documentation for more details.

Export / import option profiles

Option profile support was already available in Picard 2. Option profiles allow you to create multiple different set of configuration options and quickly switch between them. With Picard 3 such option profiles now also can be exported and imported, both as a backup or to share them with others. If an option profile is exported in order to share it, the export will exclude any configuration options that are considered secret or private (such as authentication data). For details see the User Guide under Backing Up and Sharing Profiles.

Exporting and importing option profiles can also be done using the new picard-cli command line utility, see below.

We are excited to see how this feature will be used by the community.

Operating system support

Picard is now available for macOS ARM64 aka Apple silicon. While it was previously possible to run Picard on such systems using Apples Rosetta 2 emulation layer, the native builds offer better performance. Please note that there are separate downloads for the ARM64 and Intel versions of Picard. Please make sure to download the file appropriate for your hardware.

Due to the updated dependencies, in particular Picard now using PyQt6 / Qt6 and the minimum supported Python version being 3.10, support for older operating systems had to be dropped.
Picard 3 requires Windows 10 or later or macOS 13 or later. Linux users should have Qt 6.6 or later and at least Python 3.10 available.

CD disc lookup from tags and more log file import options

The existing functionality to lookup disc IDs from CD ripping log files was extended to support raw SCSI TOC data files as written by redumper.

For files ripped with iTunes / Apple Music and which contain the CD TOC as a iTunes_CDDB_1 tag it is now possible to perform a disc ID lookup directly from the tag. This is explained in detail in the User Guide under Lookup iTunes Tag.

Synchronized lyrics

Picard 3 provides initial support for synchronized lyrics. It can load and save a syncedlyrics tag from ID3 and WMA tags. The synchronized lyrics are using the LRC format to describe the timings. We plan to extend support for synchronized lyrics with future updates to support more tagging formats and lyrics features.

Translation of artist, release and track titles by aliases

The existing system to translate artist names using aliases has been extended to also provide translations of album and track titles. Also the old behavior of always falling back to using the sort name as translation has been made optional and is now disabled by default. See the Metadata Options documentation for details.

Screenshot of a part of the Metadata options page showing the new options to select if and when to translate artist names as well as album and track titles.

The new metadata translation options, which allow to translate artist names as well as album and track titles.

Improved release matching

The algorithm for matching files to releases and recordings after a Lookup was totally reworked and greatly improved.
Overall we expect the new algorithm to give better results. There is now also an extensive test framework in-place that allows us to detect regressions in the matching performance in the future.

ISRC lookup and submission

Picard now supports extracting ISRCs from CDs and adding them to loaded releases. It can also submit ISRCs loaded from disc or already present in the tags back to MusicBrainz. If new ISRCs are present for matched files, the ISRC submission dialog can be opened from the menu in File → Submit ISRCs. For details see the documentation on Submitting ISRCs.

The new ISRC submission dialog. It will show which new ISRCs are available for a recording and can submit those ISRCs back to MusicBrainz.

Individual files with an existing ISRC tag can also be looked up by ISRC using Lookup by… → Lookup by ISRC from the file’s context menu.

Command line utility “picard-cli”

Picard 3 comes with a new command line utility “picard-cli”. Currently this allows managing plugins and exporting/importing option profiles from the command line. Run picard-cli --help for more details.

Updated Picard User Guide

The online documentation available at https://picard-docs.musicbrainz.org has been updated for all of the changes in Picard 3. It is now hosted on ReadTheDocs and available in English, French and Dutch. When opening documentation pages from inside Picard the links will use the language matching Picard’s user interface language, if available. You can help translate the Picard User Guide into your language, see the instructions for Picard, Picard Website and Picard User Guide Internationalization.

Performance and memory optimizations

This release includes several optimizations to improve the speed and responsiveness of Picard during certain operations and to reduce memory use.

And more…

There have been many more improvements and bug fixes: Picard 3 is the product of roughly three years of work that began in late 2023 with the move to PyQt6: 687 merged pull requests, nearly 6,800 commits from over 100 contributors (including 40-ish translators), and almost 400 resolved tickets.

A good part of the code was rewritten, to ease maintenance and future evolution. Static typing is now used (but covering the whole code will take some time, we focused on important parts).
Test coverage is also much larger.

Please see the change log for a complete list of changes.

Download

Picard 3.0 is available for download from the download page of the Picard website.

Please note: For Windows users installing from the Windows Store the update to version 3.0 is not yet available. We will provide a Windows Store release with an update shortly. The Linux Flatpak package is maintained separately and will be updated soon.

Picard is free software and the source code is available on GitHub.

Acknowledgements

Getting this new major version of Picard ready was a huge effort, one that wouldn’t have been possible without the many contributors. Thanks to everyone who helped with code, translation or reporting issues and feature requests.

Code contributions by Adela Chang, Akshat Khatri, Anton Kesy, Arnab Chakraborty, Bob Swift, Bryan Roessler, David Kellner, Deepak Kumar, Francisco Lisboa, FRC, Goldmaster, Greg Myers, Deepak Tiwari, James Le Cuirot, joncrall, João Sousa , Julian Anderson, Kajal Soni, knguyen, krotka, Laurent Monin, Lctrs, leo60228, Marethyun, Martin, Martin Natano, metaisfacil, OscarL, Philipp Wolfer, pranavsource1, Rakim, ripstream, Sanskar Mittal, Alex, ShubhamBhut, soniikajal, Sophist, StevilKnevil, nullHawk, thekiefs, Thuna, Giorgio Fontanive, x11x and Yohay.

Translations were updated by:

Albanian: Besnik
Arabic: alaishaq
Catalan: Marc Riera
Chinese (Simplified Han script): imgradeone, KenParker_CN and Nebulain
Chinese (Traditional Han script): BestSteve, Iceman1415 and silentbird
Czech: Fjuro
Dutch: mfmeulenbelt, RandomMushroom128 and toineenzo
English (United Kingdom): glawie
Estonian: Priit Jõerüüt
Finnish: Jaakko Perttilä
French: Laurent Monin and rez00
Galician: ninjum
Georgian: NorwayFun
German: bababasti, chaban, Gsam3, janrieger, Philipp Wolfer and st.esser
Greek: Theo Asimakopoulos
Hungarian: hildgyorgy and pXF
Italian: GABG and salo.rock
Japanese: marudosurdo, RT2231, shuuji3 and zatto13
Korean: coldified_
Lithuanian: Vaclovas Intas
Malay: Jeluang
Norwegian Bokmål: “ApeKattQuest, MonkeyPython” and Metafono
Polish: ankhedonic, Echelon and Michal77
Portuguese: evarfino and joaodtx
Portuguese (Brazil): cristian_emanuel and vitortle
Russian: Dimlbur, wileyfoxyx and Wonordel
Spanish: deusdagon, Dino RTX, jaimeMF and Nicolás Tamargo
Spanish (Latin America): MichTheOcelot
Swedish: blueday
Turkish: brtc and dirt3009
Ukrainian: Arhidimon, emptybrainz, Nerten and oleh_hishak

Get in touch

Please use the MetaBrainz community forums and the ticket system to give feedback, suggest new features or report bugs.

Breaking changes

  • Support for older operating system versions was dropped due to the update to Qt6 and newer Python versions. That means the minimum supported Windows version is now Windows 10, while for macOS you need macOS 13 “Ventura” or later. Users on older operating systems, who cannot or do not want to update their OS, should continue to use Picard 2. We plan to do at least one final Picard 2 release with important fixes to allow this version to be continued to be used.
  • Not all plugins from Picard 2 are available. Several important ones have been ported, but some old plugins were unmaintained or do not meet the quality standards expected. If you miss a specific plugin you rely on please let us know in the community forums.
  • The artist sort name by default is no longer used as a fallback to provide a “translated” name. The previous behavior resulted in several bugs being reported with wrong artist names after translation. If you relied on the old behavior you can restore it by enabling “Use artist sort name for translation” in the Metadata Options.
  • Passing a parameter to the $matchedtracks() scripting function now is an error. Previously it was possible to pass a parameter to this function (e.g. $matchedtracks(%artist%)), but it had no effect.
  • The lyrics and comments tags now always support a language, which is used when the tag is being loaded from or saved to ID3. The format is lyrics:lang:description / comment:lang:description, where lang is a 3 letter ISO code and description an additional descriptive text. If the language is being omitted, the separating colons are still mandatory, e.g. comment::description.

Known issues

  • On macOS, in some setups, the global menu is not showing check marks for checkable menu items. It is currently unclear which exact setups are affected by this. If you experience this issue, please reach out with details on your macOS version (see PICARD-2509).
  • Restoring a large session takes a significant amount of time and causes the UI to become unresponsive. We plan to improve this in future releases (see PICARD-3460).
  • The picard-cli command line tool is not available on macOS when being installed as an app. However, it can be installed by installing Picard from PyPI.

Change log

Since the last stable Picard release 2.13.3 there have been 14 pre-releases for Picard 3. During the development we addressed 393 tickets to fix bugs, add features and improve existing functionality. Please see the detailed change log on the website for a full list of changes.

The Daily Front Page 20 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Containers From First Principles
article

Linux containers in 500 lines of code (2016)

by mkornaukhov·▲ 112 points·22 comments·blog.lizzie.io ↗
I wanted specifically to find a minimal set of restrictions to run untrusted code.

I've used Linux containers directly and indirectly for years, but I wanted to become more familiar with them. So I wrote some code. This used to be 500 lines of code, I swear, but I've revised it some since publishing; I've ended up with about 70 lines more.

I wanted specifically to find a minimal set of restrictions to run untrusted code. This isn't how you should approach containers on anything with any exposure: you should restrict everything you can. But I think it's important to know which permissions are categorically unsafe! I've tried to back up things I'm saying with links to code or people I trust, but I'd love to know if I missed anything.

This is a noweb-style piece of literate code. References named <<x>> will be expanded to the code block named x. You can find the tangled source here. This document is an orgmode document, you can find its source here. This document and this code are licensed under the GPLv3; you can find its source here.

Container setup

There are several complementary and overlapping mechanisms that make up modern Linux containers. Roughly,

  • namespaces are used to group kernel objects into different sets that can be accessed by specific process trees. For example, pid namespaces limit the view of the process list to the processes within the namespace. There are a couple of different kind of namespaces. I'll go into this more later.
  • capabilities are used here to set some coarse limits on what uid 0 can do.
  • cgroups is a mechanism to limit usage of resources like memory, disk io, and cpu-time.
  • setrlimit is another mechanism for limiting resource usage. It's older than cgroups, but can do some things cgroups can't.

These are all Linux kernel mechanisms. Seccomp, capabilities, and setrlimit are all done with system calls. cgroups is accessed through a filesystem.

There's a lot here, and the scope of each mechanism is pretty unclear. They overlap a lot and it's tricky to find the best way to limit things. User namespaces are somewhat new, and promise to unify a lot of this behavior. But unfortunately compiling the kernel with user namespaces enabled complicates things. Compiling with user namespaces changes the semantics of capabilities system-wide, which could cause more problems or at least confusion. There have been a large number of privilege-escalation bugs exposed by user namespaces. "Understanding and Hardening Linux Containers" explains

Despite the large upsides the user namespace provides in terms of security, due to the sensitive nature of the user namespace, somewhat conflicting security models and large amount of new code, several serious vulnerabilities have been discovered and new vulnerabilities have unfortunately continued to be discovered. These deal with both the implementation of user namespaces itself or allow the illegitimate or unintended use of the user namespace to perform a privilege escalation. Often these issues present themselves on systems where containers are not being used, and where the kernel version is recent enough to support user namespaces.

It's turned off by default in Linux at the time of this writing, but many distributions apply patches to turn it on in a limited way.

But all of these issues apply to hosts with user namespaces compiled in; it doesn't really matter whether we use user namespaces or not, especially since I'll be preventing nested user namespaces. So I'll only use a user namespace if they're available.

(The user-namespace handling in this code was originally pretty broken. Jann Horn in particular gave great feedback. Thanks!)

contained.c

This program can be used like this, to run /misc/img/bin/sh in /misc/img as root:

[lizzie@empress l-c-i-500-l]$ sudo ./contained -m ~/misc/busybox-img/ -u 0 -c /bin/sh
=> validating Linux version...4.7.10.201610222037-1-grsec on x86_64.
=> setting cgroups...memory...cpu...pids...blkio...done.
=> setting rlimit...done.
=> remounting everything with MS_PRIVATE...remounted.
=> making a temp directory and a bind mount there...done.
=> pivoting root...done.
=> unmounting /oldroot.oQ5jOY...done.
=> trying a user namespace...writing /proc/32627/uid_map...writing /proc/32627/gid_map...done.
=> switching to uid 0 / gid 0...done.
=> dropping capabilities...bounding...inheritable...done.
=> filtering syscalls...done.
/ # whoami
root
/ # hostname
05fe5c-three-of-pentacles
/ # exit
=> cleaning cgroups...done.

So, a skeleton for it:

/* -*- compile-command: "gcc -Wall -Werror -lcap -lseccomp contained.c -o contained" -*- */
/* This code is licensed under the GPLv3. You can find its text here:
   https://www.gnu.org/licenses/gpl-3.0.en.html */


#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <sched.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/capability.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <linux/capability.h>
#include <linux/limits.h>

struct child_config {
	int argc;
	uid_t uid;
	int fd;
	char *hostname;
	char **argv;
	char *mount_dir;
};

<<capabilities>>

<<mounts>>

<<syscalls>>

<<resources>>

<<child>>

<<choose-hostname>>

int main (int argc, char **argv)
{
	struct child_config config = {0};
	int err = 0;
	int option = 0;
	int sockets[2] = {0};
	pid_t child_pid = 0;
	int last_optind = 0;
	while ((option = getopt(argc, argv, "c:m:u:"))) {
		switch (option) {
		case 'c':
			config.argc = argc - last_optind - 1;
			config.argv = &argv[argc - config.argc];
			goto finish_options;
		case 'm':
			config.mount_dir = optarg;
			break;
		case 'u':
			if (sscanf(optarg, "%d", &config.uid) != 1) {
				fprintf(stderr, "badly-formatted uid: %s\n", optarg);
				goto usage;
			}
			break;
		default:
			goto usage;
		}
		last_optind = optind;
	}
finish_options:
	if (!config.argc) goto usage;
	if (!config.mount_dir) goto usage;

<<check-linux-version>>

	char hostname[256] = {0};
	if (choose_hostname(hostname, sizeof(hostname)))
		goto error;
	config.hostname = hostname;

<<namespaces>>

	goto cleanup;
usage:
	fprintf(stderr, "Usage: %s -u -1 -m . -c /bin/sh ~\n", argv[0]);
error:
	err = 1;
cleanup:
	if (sockets[0]) close(sockets[0]);
	if (sockets[1]) close(sockets[1]);
	return err;
}

Since I'll be blacklisting system calls and capabilities, it's important to make sure there aren't any new ones.

	fprintf(stderr, "=> validating Linux version...");
	struct utsname host = {0};
	if (uname(&host)) {
		fprintf(stderr, "failed: %m\n");
		goto cleanup;
	}
	int major = -1;
	int minor = -1;
	if (sscanf(host.release, "%u.%u.", &major, &minor) != 2) {
		fprintf(stderr, "weird release format: %s\n", host.release);
		goto cleanup;
	}
	if (major != 4 || (minor != 7 && minor != 8)) {
		fprintf(stderr, "expected 4.7.x or 4.8.x: %s\n", host.release);
		goto cleanup;
	}
	if (strcmp("x86_64", host.machine)) {
		fprintf(stderr, "expected x86_64: %s\n", host.machine);
		goto cleanup;
	}
	fprintf(stderr, "%s on %s.\n", host.release, host.machine);

(This had a bug. captainjey on reddit let me know. Thanks!)

And I wasn't quite at 500 lines of code, so I thought I had some space to build nice hostnames.

int choose_hostname(char *buff, size_t len)
{
	static const char *suits[] = { "swords", "wands", "pentacles", "cups" };
	static const char *minor[] = {
		"ace", "two", "three", "four", "five", "six", "seven", "eight",
		"nine", "ten", "page", "knight", "queen", "king"
	};
	static const char *major[] = {
		"fool", "magician", "high-priestess", "empress", "emperor",
		"hierophant", "lovers", "chariot", "strength", "hermit",
		"wheel", "justice", "hanged-man", "death", "temperance",
		"devil", "tower", "star", "moon", "sun", "judgment", "world"
	};
	struct timespec now = {0};
	clock_gettime(CLOCK_MONOTONIC, &now);
	size_t ix = now.tv_nsec % 78;
	if (ix < sizeof(major) / sizeof(*major)) {
		snprintf(buff, len, "%05lx-%s", now.tv_sec, major[ix]);
	} else {
		ix -= sizeof(major) / sizeof(*major);
		snprintf(buff, len,
			 "%05lxc-%s-of-%s",
			 now.tv_sec,
			 minor[ix % (sizeof(minor) / sizeof(*minor))],
			 suits[ix / (sizeof(minor) / sizeof(*minor))]);
	}
	return 0;
}

Namespaces

clone is the system call behind fork() et al. It's also the key to all of this. Conceptually we want to create a process with different properties than its parent: it should be able to mount a different /, set its own hostname, and do other things. We'll specify all of this by passing flags to clone.

The child needs to send some messages to the parent, so we'll initialize a socketpair, and then make sure the child only receives access to one.

	if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, sockets)) {
		fprintf(stderr, "socketpair failed: %m\n");
		goto error;
	}
	if (fcntl(sockets[0], F_SETFD, FD_CLOEXEC)) {
		fprintf(stderr, "fcntl failed: %m\n");
		goto error;
	}
	config.fd = sockets[1];

But first we need to set up room for a stack. We'll execve later, which will actually set up the stack again, so this is only temporary.

	#define STACK_SIZE (1024 * 1024)

	char *stack = 0;
	if (!(stack = malloc(STACK_SIZE))) {
		fprintf(stderr, "=> malloc failed, out of memory?\n");
		goto error;
	}

We'll also prepare the cgroup for this process tree. More on this later.

	if (resources(&config)) {
		err = 1;
		goto clear_resources;
	}

We'll namespace the mounts, pids, IPC data structures, network devices, and hostname / domain name. I'll go into these more in the code for capabilities, cgroups, and syscalls.

	int flags = CLONE_NEWNS
		| CLONE_NEWCGROUP
		| CLONE_NEWPID
		| CLONE_NEWIPC
		| CLONE_NEWNET
		| CLONE_NEWUTS;

Stacks on x86, and almost everything else Linux runs on, grow downwards, so we'll add STACK_SIZE to get a pointer just below the end. We also | the flags with SIGCHLD so that we can wait on it.

	if ((child_pid = clone(child, stack + STACK_SIZE, flags | SIGCHLD, &config)) == -1) {
		fprintf(stderr, "=> clone failed! %m\n");
		err = 1;
		goto clear_resources;
	}

Close and zero the child's socket, so that if something breaks then we don't leave an open fd, possibly causing the child to or the parent to hang.

	close(sockets[1]);
	sockets[1] = 0;

The parent process will configure the child's user namespace and then pause until the child process tree exits.

#define USERNS_OFFSET 10000
#define USERNS_COUNT 2000

int handle_child_uid_map (pid_t child_pid, int fd)
{
	int uid_map = 0;
	int has_userns = -1;
	if (read(fd, &has_userns, sizeof(has_userns)) != sizeof(has_userns)) {
		fprintf(stderr, "couldn't read from child!\n");
		return -1;
	}
	if (has_userns) {
		char path[PATH_MAX] = {0};
		for (char **file = (char *[]) { "uid_map", "gid_map", 0 }; *file; file++) {
			if (snprintf(path, sizeof(path), "/proc/%d/%s", child_pid, *file)
			    > sizeof(path)) {
				fprintf(stderr, "snprintf too big? %m\n");
				return -1;
			}
			fprintf(stderr, "writing %s...", path);
			if ((uid_map = open(path, O_WRONLY)) == -1) {
				fprintf(stderr, "open failed: %m\n");
				return -1;
			}
			if (dprintf(uid_map, "0 %d %d\n", USERNS_OFFSET, USERNS_COUNT) == -1) {
				fprintf(stderr, "dprintf failed: %m\n");
				close(uid_map);
				return -1;
			}
			close(uid_map);
		}
	}
	if (write(fd, & (int) { 0 }, sizeof(int)) != sizeof(int)) {
		fprintf(stderr, "couldn't write: %m\n");
		return -1;
	}
	return 0;
}

The child process will send a message to the parent process about whether it should set uid and gid mappings. If that works, it will setgroups, setresgid, and setresuid. Both setgroups and setresgid are necessary here since there are two separate group mechanisms on Linux. I'm also assuming here that every uid has a corresponding gid, which is common but not necessarily universal.

int userns(struct child_config *config)
{
	fprintf(stderr, "=> trying a user namespace...");
	int has_userns = !unshare(CLONE_NEWUSER);
	if (write(config->fd, &has_userns, sizeof(has_userns)) != sizeof(has_userns)) {
		fprintf(stderr, "couldn't write: %m\n");
		return -1;
	}
	int result = 0;
	if (read(config->fd, &result, sizeof(result)) != sizeof(result)) {
		fprintf(stderr, "couldn't read: %m\n");
		return -1;
	}
	if (result) return -1;
	if (has_userns) {
		fprintf(stderr, "done.\n");
	} else {
		fprintf(stderr, "unsupported? continuing.\n");
	}
	fprintf(stderr, "=> switching to uid %d / gid %d...", config->uid, config->uid);
	if (setgroups(1, & (gid_t) { config->uid }) ||
	    setresgid(config->uid, config->uid, config->uid) ||
	    setresuid(config->uid, config->uid, config->uid)) {
		fprintf(stderr, "%m\n");
		return -1;
	}
	fprintf(stderr, "done.\n");
	return 0;
}

And this is where the child process from clone will end up. We'll perform all of our setup, switch users and groups, and then load the executable. The order is important here: we can't change mounts without certain capabilities, we can't unshare after we limit the syscalls, etc.

int child(void *arg)
{
	struct child_config *config = arg;
	if (sethostname(config->hostname, strlen(config->hostname))
	    || mounts(config)
	    || userns(config)
	    || capabilities()
	    || syscalls()) {
		close(config->fd);
		return -1;
	}
	if (close(config->fd)) {
		fprintf(stderr, "close failed: %m\n");
		return -1;
	}
	if (execve(config->argv[0], config->argv, NULL)) {
		fprintf(stderr, "execve failed! %m.\n");
		return -1;
	}
	return 0;
}

Capabilties

capabilities subdivide the property of "being root" on Linux. It's useful to compartmentalize privileges so that, for example a process can allocate network devices (CAP_NET_ADMIN) but not read all files (CAP_DAC_OVERRIDE). I'll use them here to drop the ones we don't want.

But not all of "being root" is subvidivided into capabilities. For example, writing to parts of procfs is allowed by root even after having dropped capabilities. There are a lot of things like this: this is part of why need other restrictions beside capabilities.

It's also important to think about how we're dropping capabilities. man 7 capabilities has an algorithm for us:

During  an   execve(2),  the   kernel calculates   the  new
capabilities of the process using the following algorithm:

    P'(ambient) = (file is privileged) ? 0 : P(ambient)

    P'(permitted) = (P(inheritable) & F(inheritable)) |
                            (F(permitted) & cap_bset) | P'(ambient)

    P'(effective) = F(effective) ? P'(permitted) : P'(ambient)

    P'(inheritable) = P(inheritable)    [i.e., unchanged]

where:

    P         denotes the  value of a thread  capability set
                before the execve(2)

    P'        denotes the value of a thread  capability set
                after the execve(2)

    F         denotes a file capability set

    cap_bset  is the  value of  the capability  bounding set
                (described below).

We'd like P'(ambient) and P(inheritable) to be empty, and P'(permitted) and P(effective) to only include the capabilities above. This is achievable by doing the following

  • Clearing our own inheritable set. This clears the ambient set; man 7 capabilities says "The ambient capability set obeys the invariant that no capability can ever be ambient if it is not both permitted and inheritable." This also clears the child's inheritable set.
  • Clearing the bounding set. This limits the file capabilities we'll gain when we execve, and the rest are limited by clearing the inheritable and ambient sets.

If we were to only drop our own effective, permitted and inheritable sets, we'd regain the permissions in the child file's capabilities. This is how bash can call ping, for example.

Dropped capabilities

int capabilities()
{
	fprintf(stderr, "=> dropping capabilities...");

CAP_AUDIT_CONTROL, _READ, and _WRITE allow access to the audit system of the kernel (i.e. functions like audit_set_enabled, usually used with auditctl). The kernel prevents messages that normally require CAP_AUDIT_CONTROL outside of the first pid namespace, but it does allow messages that would require CAP_AUDIT_READ and CAP_AUDIT_WRITE from any namespace. So let's drop them all. We especially want to drop CAP_AUDIT_READ, since it isn't namespaced and may contain important information, but CAP_AUDIT_WRITE may also allow the contained process to falsify logs or DOS the audit system.

	int drop_caps[] = {
		CAP_AUDIT_CONTROL,
		CAP_AUDIT_READ,
		CAP_AUDIT_WRITE,

CAP_BLOCK_SUSPEND lets programs prevent the system from suspending, either with EPOLLWAKEUP or /proc/sys/wake_lock. Supend isn't namespaced, so we'd like to prevent this.

		CAP_BLOCK_SUSPEND,

CAP_DAC_READ_SEARCH lets programs call open_by_handle_at with an arbitrary struct file_handle *. struct file_handle is in theory an opaque type, but in practice it corresponds to inode numbers. So it's easy to brute-force them, and read arbitrary files. This was used by Sebastian Krahmer to write a program to read arbitrary system files from within Docker in 2014.

		CAP_DAC_READ_SEARCH,

CAP_FSETID, without user namespacing, allows the process to modify a setuid executable without removing the setuid bit. This is pretty dangerous! It means that if we include a setuid binary in a container, it's easy for us to accidentally leave a dangerous setuid root binary on our disk, which any user can use to escalate privileges.

		CAP_FSETID,

CAP_IPC_LOCK can be used to lock more of a process' own memory than would normally be allowed, which could be a way to deny service.

		CAP_IPC_LOCK,

CAP_MAC_ADMIN and CAP_MAC_OVERRIDE are used by the mandatory acess control systems Apparmor, SELinux, and SMACK to restrict access to their settings. These aren't namespaced, so they could be used by the contained programs to circumvent system-wide access control.

		CAP_MAC_ADMIN,
		CAP_MAC_OVERRIDE,

CAP_MKNOD, without user namespacing, allows programs to create device files corresponding to real-world devices. This includes creating new device files for existing hardware. If this capability were not dropped, a contained process could re-create the hard disk device, remount it, and read or write to it.

		CAP_MKNOD,

I was worried that CAP_SETFCAP could be used to add a capability to an executable and execve it, but it's not actually possible for a process to set capabilities it doesn't have. But! An executable altered this way could be executed by any unsandboxed user, so I think it unacceptably undermines the security of the system.

		CAP_SETFCAP,

CAP_SYSLOG lets users perform destructive actions against the syslog. Importantly, it doesn't prevent contained processes from reading the syslog, which could be risky. It also exposes kernel addresses, which could be used to circumvent kernel address layout randomization.

		CAP_SYSLOG,

CAP_SYS_ADMIN allows many behaviors! We don't want most of them (mount, vm86, etc). Some would be nice to have (sethostname, mount for bind mounts…) but the extra complexity doesn't seem worth it.

		CAP_SYS_ADMIN,

CAP_SYS_BOOT allows programs to restart the system (the reboot syscall) and load new kernels (the kexec_load and kexec_file syscalls). We absolutely don't want this. reboot is user-namespaced, and the kexec* functions only work in the root user namespace, but neither of those help us.

		CAP_SYS_BOOT,

CAP_SYS_MODULE is used by the syscalls delete_module, init_module, finit_module, by the code for kmod, and by the code for loading device modules with ioctl.

		CAP_SYS_MODULE,

CAP_SYS_NICE allows processes to set higher priority on given pids than the default. The default kernel scheduler doesn't know anything about pid namespaces, so it's possible for a contained process to deny service to the rest of the system.

		CAP_SYS_NICE,

CAP_SYS_RAWIO allows full access to the host systems memory with /proc/kcore, /dev/mem, and /dev/kmem, but a contained process would need mknod to access these within the namespace. But it also allows things like iopl and ioperm, which give raw access to the IO ports.

		CAP_SYS_RAWIO,

CAP_SYS_RESOURCE specifically allows circumventing kernel-wide limits, so we probably should drop it. But I don't think this can do more than DOS the kernel, in general.

		CAP_SYS_RESOURCE,

CAP_SYS_TIME: setting the time isn't namespaced, so we should prevent contained processes from altering the system-wide time.

		CAP_SYS_TIME,

CAP_WAKE_ALARM, like CAP_BLOCK_SUSPEND, lets the contained process interfere with suspend, and we'd like to prevent that.

		CAP_WAKE_ALARM
	};
	size_t num_caps = sizeof(drop_caps) / sizeof(*drop_caps);
	fprintf(stderr, "bounding...");
	for (size_t i = 0; i < num_caps; i++) {
		if (prctl(PR_CAPBSET_DROP, drop_caps[i], 0, 0, 0)) {
			fprintf(stderr, "prctl failed: %m\n");
			return 1;
		}
	}
	fprintf(stderr, "inheritable...");
	cap_t caps = NULL;
	if (!(caps = cap_get_proc())
	    || cap_set_flag(caps, CAP_INHERITABLE, num_caps, drop_caps, CAP_CLEAR)
	    || cap_set_proc(caps)) {
		fprintf(stderr, "failed: %m\n");
		if (caps) cap_free(caps);
		return 1;
	}
	cap_free(caps);
	fprintf(stderr, "done.\n");
	return 0;
}

Retained Capabilities

It's important to keep track of the capabilities I'm not dropping, too.

I've heard multiple places that CAP_DAC_OVERRIDE might expose the same functionality as CAP_DAC_READ_SEARCH (i.e. open_by_handle_at), but as far as I can tell that isn't true. shocker.c doesn't get anywhere with only CAP_DAC_OVERRIDE, and the only usage in the kernel is in the Unix permission-checking code. So my understanding is that CAP_DAC_OVERRIDE on its own doesn't allow processes to read outside of their mount namespaces ("DAC" or "Discretionary Access Control" refers here to ordinary unix permissions).

CAP_FOWNER, CAP_LEASE, and CAP_LINUX_IMMUTABLE all operate on files inside of the mount namespace.

Likewise, CAP_SYS_PACCT allows processes to switch accounting on and off for itself. The acct system call takes a path to log to (which must be within the mount namespace), and only operates on the calling process. We're not using process accounting in our containerization, so turning it off should be harmless as well.

CAP_IPC_OWNER is only used by functions that respect IPC namespaces; since we're in a separate IPC namespace from the host, we can allow this.

CAP_NET_ADMIN lets processes create network devices; CAP_NET_BIND_SERVICE lets processes bind to low ports on those devices; CAP_NET_RAW lets processes send raw packets on those devices. Since we're going to isolate the networking with a virtual bridge, and the contained process is inside of a network namespace, these shouldn't be an issue. I was wondering whether we could recreate an existing device like mknod does, but I don't think it's possible.

CAP_SYS_PTRACE doesn't allow ptrace across pid namespaces. CAP_KILL doesn't allow signals across pid namespaces.

CAP_SETUID and CAPSETGID have similar behaviors:

  • Make arbitrary manipulations of process UIDS and GIDs and supplementary GID list, which will only apply to pids in the namespace.
  • forge UID (GID) when passing socket credentials via UNIX domain sockets the mount namespace should prevent us from reading the host system's unix domain sockets.
  • write a user(group ID) mapping in a user namespace (see user_namespaces(7)): this is /proc/self/uid_map, which will be hidden inside the container.

CAP_SETPCAP only lets processes add or drop capabilities they already effectively have; man 7 capabilities says

If file capabilities are supported: add any capability from the calling thread's bounding set to its inheritable set; drop capabilities from the bounding set (via prctl(2) PR_CAPBSET_DROP); make changes to the securebits flags.

We've dropped everything relevant from the bounding set, and dropping further capabilities should be harmless.

CAP_SYS_CHROOT is traditionally abused by changing root to a directory with a setuid root binary and tampered-with dynamic libraries. Additionally, it can be used to escape a chroot "jail". Neither of those should be relevant in our setup so this should be harmless.

Brad Spengler, in "False Boundaries and Arbitrary Code Execution" says that CAP_SYS_TTYCONFIG can "temporarily change the keyboard mapping of an administrator's tty via the KDSETKEYCODE ioctl to cause a different command to be executed than intended", but again this is an ioctl against a device that should be impossible to access within the mount namespace.

Mounts

The child process is in its own mount namespace, so we can unmount things that it specifically shouldn't have access to. Here's how:

  • Create a temporary directory, and one inside of it.
  • Bind mount of the user argument onto the temporary directory
  • pivot_root, making the bind mount our root and mounting the old root onto the inner temporary directory.
  • umount the old root, and remove the inner temporary directory.

But first we'll remount everything with MS_PRIVATE. This is mostly a convenience, so that the bind mount is invisible outside of our namespace.

int pivot_root(const char *new_root, const char *put_old)
{
	return syscall(SYS_pivot_root, new_root, put_old);
}

int mounts(struct child_config *config)
{
	fprintf(stderr, "=> remounting everything with MS_PRIVATE...");
	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
		fprintf(stderr, "failed! %m\n");
		return -1;
	}
	fprintf(stderr, "remounted.\n");

	fprintf(stderr, "=> making a temp directory and a bind mount there...");
	char mount_dir[] = "/tmp/tmp.XXXXXX";
	if (!mkdtemp(mount_dir)) {
		fprintf(stderr, "failed making a directory!\n");
		return -1;
	}

	if (mount(config->mount_dir, mount_dir, NULL, MS_BIND | MS_PRIVATE, NULL)) {
		fprintf(stderr, "bind mount failed!\n");
		return -1;
	}

	char inner_mount_dir[] = "/tmp/tmp.XXXXXX/oldroot.XXXXXX";
	memcpy(inner_mount_dir, mount_dir, sizeof(mount_dir) - 1);
	if (!mkdtemp(inner_mount_dir)) {
		fprintf(stderr, "failed making the inner directory!\n");
		return -1;
	}
	fprintf(stderr, "done.\n");

	fprintf(stderr, "=> pivoting root...");
	if (pivot_root(mount_dir, inner_mount_dir)) {
		fprintf(stderr, "failed!\n");
		return -1;
	}
	fprintf(stderr, "done.\n");

	char *old_root_dir = basename(inner_mount_dir);
	char old_root[sizeof(inner_mount_dir) + 1] = { "/" };
	strcpy(&old_root[1], old_root_dir);

	fprintf(stderr, "=> unmounting %s...", old_root);
	if (chdir("/")) {
		fprintf(stderr, "chdir failed! %m\n");
		return -1;
	}
	if (umount2(old_root, MNT_DETACH)) {
		fprintf(stderr, "umount failed! %m\n");
		return -1;
	}
	if (rmdir(old_root)) {
		fprintf(stderr, "rmdir failed! %m\n");
		return -1;
	}
	fprintf(stderr, "done.\n");
	return 0;
}

pivot_root is a system call lets us swap the mount at / with another. Glibc doesn't provide a wrapper for it, but includes a prototype in the man page. I don't really understand, but OK, we'll include our own.

It's worth noting that I'm avoiding packing and unpackaging containers. This is fertile ground for vulnerabilities; I'll count on the user to ensure that the mounted directory doesn't contain trusted or sensitive files or hard links.

System Calls

I'll be blacklisting system calls that I can demonstrate causing harm or sandbox escapes. Again this isn't the best way to do this, but it seems like the most illustrative.

Docker's documentation and default seccomp profile are reasonable sources for dangerous system calls. They also include obsolete sytem calls and calls that overlap with restricted capabilities; I'll ignore those.

Disallowed System Calls

#define SCMP_FAIL SCMP_ACT_ERRNO(EPERM)

int syscalls()
{
	scmp_filter_ctx ctx = NULL;
	fprintf(stderr, "=> filtering syscalls...");
	if (!(ctx = seccomp_init(SCMP_ACT_ALLOW))

We want to prevent new setuid / setgid executables from being created, since in the absence of user namespaces the contained process could create a setuid binary that could be used by any user to get root.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(chmod), 1,
				SCMP_A1(SCMP_CMP_MASKED_EQ, S_ISUID, S_ISUID))
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(chmod), 1,
				SCMP_A1(SCMP_CMP_MASKED_EQ, S_ISGID, S_ISGID))
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(fchmod), 1,
				SCMP_A1(SCMP_CMP_MASKED_EQ, S_ISUID, S_ISUID))
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(fchmod), 1,
				SCMP_A1(SCMP_CMP_MASKED_EQ, S_ISGID, S_ISGID))
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(fchmodat), 1,
				SCMP_A2(SCMP_CMP_MASKED_EQ, S_ISUID, S_ISUID))
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(fchmodat), 1,
				SCMP_A2(SCMP_CMP_MASKED_EQ, S_ISGID, S_ISGID))

Allowing contained processes to start new user namespaces can allow processes to gain new (albeit limited) capabilities, so we prevent it.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(unshare), 1,
				SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER))
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(clone), 1,
				SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER))

TIOCSTI allows contained processes to write to the controlling terminal.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(ioctl), 1,
				SCMP_A1(SCMP_CMP_MASKED_EQ, TIOCSTI, TIOCSTI))

The kernel keyring system isn't namespaced.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(keyctl), 0)
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(add_key), 0)
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(request_key), 0)

Before Linux 4.8, ptrace totally breaks seccomp.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(ptrace), 0)

These system calls let processes assign NUMA nodes. I don't have anything specific in mind, but I could see these being used to deny service to some other NUMA-aware application on the host.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(mbind), 0)
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(migrate_pages), 0)
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(move_pages), 0)
	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(set_mempolicy), 0)

userfaultd allows userspace to handle page faults. It doesn't require any privileges, so in theory it should be safe to be called by an unprivileged user. But it can be used to pause execution in the kernel by triggering page faults in system calls. This is an important part in some kernel exploits. It's only rarely used legitimately, so I'll disable it.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(userfaultfd), 0)

I was initially worried about perf_event_open because the Docker documentation says it "could leak a lot of information on the host", but it can't be used in our system to see information for out-of-namespace processes. But, if /proc/sys/kernel/perf_event_paranoid is less than 2, it can be used to discover kernel addresses and possibly uninitialized memory. 2 is the default since is the default since 4.6, but it can be changed, and relying on it seems like a bad idea.

	    || seccomp_rule_add(ctx, SCMP_FAIL, SCMP_SYS(perf_event_open), 0)

We'll set PR_SET_NO_NEW_PRIVS to 0. The name is a little vague: it specifically prevents setuid and setcap'd binaries from being executed with their additional privileges. This has some security benefits (it makes it harder for an unprivileged user in-container to exploit a vulnerability in a setuid or setcap executable to become in-container root, for example). But it's a little weird, and means that, for example, ping won't work in a container for an unprivileged user.

	    || seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)

And we'll actually apply it to the process, and release the context.

	    || seccomp_load(ctx)) {
		if (ctx) seccomp_release(ctx);
		fprintf(stderr, "failed: %m\n");
		return 1;
	}
	seccomp_release(ctx);
	fprintf(stderr, "done.\n");
	return 0;
}

Allowed System Calls

Here are the system calls that are disallowed by the default Docker policy but permitted by this code:

_sysctl is obsolete and disabled by default. alloc_hugepages and free_hugepages, bdflush, create_module, nfsservctl, perfctr, get_kernel_syms, and setup are not present on modern Linux.

clock_adjtime, clock_settime, and adjtime depend on CAP_SYS_TIME.

pciconfig_read and pciconfig_write and all of the side-effecting operations of quotactl are prevented by CAP_SYS_ADMIN.

get_mempolicy and getpagesize reveal information about the memory layout of the system, but they can be made by unprivileged processes, and are probably harmless. pciconfig_iobase can be made by unprivileged processes, and reveals information about PCI decvices. ustat and sysfs leak some information about the filesystems, but are nothing that I see as critical. uselib is more-or-less obsolete, but is just used for loading a shared library in userspace.

sync_file_range2 is sync_file_range with swapped argument order.

readdir is mostly obsolete, but probably harmless.

kexec_file_load and kexec_load are prevented by CAP_SYS_BOOT.

nice can only be used to lower priority without CAP_SYS_NICE.

oldfstat, oldlstat, oldolduname, oldstat, and olduname are just older versions of their respective functions. I expect them to have the same security properties as the modern ones.

perfmonctl is only available on IA-64. ppc_rtas, spu_create and spu_run, and subpage_prot are only available on PowerPC. utrap_install is only available on Sparc. kern_features is only available on Sparc64, and should be harmless anyway.

I don't believe pivot_root is a problem in our setup (but it could probably be used to circumvent path-based MAC).

preadv2 and pwritev2 are just extensions to preadv and pwritev / readv and writev, which are "scatter input" / "gather output" extensions to read and write.

Resources

We'd like to prevent badly-behaved child processes from denying service to the rest of the system. Cgroups let us limit memory and cpu time in particular; limiting the pid count and IO usage is also useful. There's a very useful document in the kernel tree about it.

The cgroup and cgroup2 filesystems are the canonical interfaces to the cgroup system. cgroup2 is a little different, and unitialized on my system, so I'll use the first version here.

Cgroup namespaces are a little different from, for example, mount namespaces. We need to create the cgroup before we enter a cgroup namespace; once we do, that cgroup will behave like the root cgroup inside of the namespace. This isn't the most relevant, since a contained process can't mount the cgroup filesystem or /proc for introspection, but it's nice to be thorough.

I'll set up a struct so I don't have to repeat myself too much, with the following instructions:

  • Set memory/$hostname/memory.limit_in_bytes, so the contained process and its child processes can't total more than 1GB memory in userspace.
  • Set memory/$hostname/memory.kmem.limit_in_bytes, so that the contained process and its child processes can't total more than 1GB memory in userspace.
  • Set cpu/$hostname/cpu.shares to 256. CPU shares are chunks of 1024; 256 * 4 = 1024, so this lets the contained process take a quarter of cpu-time on a busy system at most.
  • Set the pids/$hostname/pid.max, allowing the contained process and its children to have 64 pids at most. This is useful because there are per-user pid limits that we could hit on the host if the contained process occupies too many.
  • Set blkio/$hostname/weight to 50, so that it's lower than the rest of the system and prioritized accordingly.

I'll also add the calling process for each of {memory,cpu,blkio,pids}/$hostname/tasks by writing '0' to it.

#define MEMORY "1073741824"
#define SHARES "256"
#define PIDS "64"
#define WEIGHT "10"
#define FD_COUNT 64

struct cgrp_control {
	char control[256];
	struct cgrp_setting {
		char name[256];
		char value[256];
	} **settings;
};
struct cgrp_setting add_to_tasks = {
	.name = "tasks",
	.value = "0"
};

struct cgrp_control *cgrps[] = {
	& (struct cgrp_control) {
		.control = "memory",
		.settings = (struct cgrp_setting *[]) {
			& (struct cgrp_setting) {
				.name = "memory.limit_in_bytes",
				.value = MEMORY
			},
			& (struct cgrp_setting) {
				.name = "memory.kmem.limit_in_bytes",
				.value = MEMORY
			},
			&add_to_tasks,
			NULL
		}
	},
	& (struct cgrp_control) {
		.control = "cpu",
		.settings = (struct cgrp_setting *[]) {
			& (struct cgrp_setting) {
				.name = "cpu.shares",
				.value = SHARES
			},
			&add_to_tasks,
			NULL
		}
	},
	& (struct cgrp_control) {
		.control = "pids",
		.settings = (struct cgrp_setting *[]) {
			& (struct cgrp_setting) {
				.name = "pids.max",
				.value = PIDS
			},
			&add_to_tasks,
			NULL
		}
	},
	& (struct cgrp_control) {
		.control = "blkio",
		.settings = (struct cgrp_setting *[]) {
			& (struct cgrp_setting) {
				.name = "blkio.weight",
				.value = PIDS
			},
			&add_to_tasks,
			NULL
		}
	},
	NULL
};

Writing to the cgroups version 1 filesystem works like this:

  • In each controller, you can create a cgroup with a name with mkdir. For memory, mkdir /sys/fs/cgroup/memory/$hostname.
  • Inside of that you can write to the individual files to set values. For example, echo $MEMORY > /sys/fs/cgroup/memory/$hostname/memory.limit_in_bytes.
  • You can a pid to tasks to add the process tree to the cgroup. "0" is a special value that means "the writing process".

so I'll iterate over that structure and fill in the values.

int resources(struct child_config *config)
{
	fprintf(stderr, "=> setting cgroups...");
	for (struct cgrp_control **cgrp = cgrps; *cgrp; cgrp++) {
		char dir[PATH_MAX] = {0};
		fprintf(stderr, "%s...", (*cgrp)->control);
		if (snprintf(dir, sizeof(dir), "/sys/fs/cgroup/%s/%s",
			     (*cgrp)->control, config->hostname) == -1) {
			return -1;
		}
		if (mkdir(dir, S_IRUSR | S_IWUSR | S_IXUSR)) {
			fprintf(stderr, "mkdir %s failed: %m\n", dir);
			return -1;
		}
		for (struct cgrp_setting **setting = (*cgrp)->settings; *setting; setting++) {
			char path[PATH_MAX] = {0};
			int fd = 0;
			if (snprintf(path, sizeof(path), "%s/%s", dir,
				     (*setting)->name) == -1) {
				fprintf(stderr, "snprintf failed: %m\n");
				return -1;
			}
			if ((fd = open(path, O_WRONLY)) == -1) {
				fprintf(stderr, "opening %s failed: %m\n", path);
				return -1;
			}
			if (write(fd, (*setting)->value, strlen((*setting)->value)) == -1) {
				fprintf(stderr, "writing to %s failed: %m\n", path);
				close(fd);
				return -1;
			}
			close(fd);
		}
	}
	fprintf(stderr, "done.\n");

I'll also lower the hard limit on the number of file descriptors. The file descriptor number, like the number of pids, is per-user, and so we want to prevent in-container process from occupying all of them. Setting the hard limit sets a permanent upper bound for this process tree, since I've dropped CAP_SYS_RESOURCE.

	fprintf(stderr, "=> setting rlimit...");
	if (setrlimit(RLIMIT_NOFILE,
		      & (struct rlimit) {
			.rlim_max = FD_COUNT,
			.rlim_cur = FD_COUNT,
		})) {
		fprintf(stderr, "failed: %m\n");
		return 1;
	}
	fprintf(stderr, "done.\n");
	return 0;
}

We'd also like to clean up the cgroup for this hostname. There's built-in functionality for this, but we would need to change system-wide values to do it cleanly. Since we have the contained process waiting on the contained process, it's simple to do it this way. First we move the contained process back into the root tasks; then, since the child process is finished, and leaving the pid namespace SIGKILLS its children, the tasks is empty. We can safely rmdir at this point.

int free_resources(struct child_config *config)
{
	fprintf(stderr, "=> cleaning cgroups...");
	for (struct cgrp_control **cgrp = cgrps; *cgrp; cgrp++) {
		char dir[PATH_MAX] = {0};
		char task[PATH_MAX] = {0};
		int task_fd = 0;
		if (snprintf(dir, sizeof(dir), "/sys/fs/cgroup/%s/%s",
			     (*cgrp)->control, config->hostname) == -1
		    || snprintf(task, sizeof(task), "/sys/fs/cgroup/%s/tasks",
				(*cgrp)->control) == -1) {
			fprintf(stderr, "snprintf failed: %m\n");
			return -1;
		}
		if ((task_fd = open(task, O_WRONLY)) == -1) {
			fprintf(stderr, "opening %s failed: %m\n", task);
			return -1;
		}
		if (write(task_fd, "0", 2) == -1) {
			fprintf(stderr, "writing to %s failed: %m\n", task);
			close(task_fd);
			return -1;
		}
		close(task_fd);
		if (rmdir(dir)) {
			fprintf(stderr, "rmdir %s failed: %m", dir);
			return -1;
		}
	}
	fprintf(stderr, "done.\n");
	return 0;
}

Networking

Container networking takes a little too much explanation for this space. It usually works like this:

  • Create a bridge device.
  • Create a virtual ethernet pair and attach one end to the bridge.
  • Put the other end in the network namespace.
  • For outside networking access, the host needs to be set to forward (and possibly NAT) packets.

Having multiple contained processes sharing a bridge device would mean they're both on the same LAN from the host's perspective. So ARP spoofing is a recurring issue with containers that work this way.

The canonical way to do this from C is the rtnetlink interface; it would probably be easier to use ip link ....

We could also limit the network usage with the net_prio cgroup controller.

The Daily Front Page 21 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — When Memory Pages Out
article

A 40ms Go garbage collector pause caused by swap

by shellpipe·▲ 110 points·133 comments·frn.sh ↗
swap doesn’t just make the allocation slower; if GC metadata gets paged out, you have turned memory pressure into a stop-the-world latency spike.

I’m writing this so you don’t slap your forehead like I almost did when I decided to run swap in production to absorb memory spikes.

I had a cgroup with two processes: one is a Go process that calls io.ReadAll and then proto.Unmarshal, creating a blob and then a graph struct (which is marked as scan by Go’s allocator). The other process is an HTTP server that mostly stays quiet.

Whenever the collector runs, it reads those scan spans, pointer by pointer, and decides what to do with them. So I thought: ok, under memory pressure, the kernel is going to evict pages to the swap device, but since the eviction is per cgroup, and not per process, both processes’ pages are going to be evicted - so there is only a small chance that this will turn into a sad dance of swap-in and swap-out between the kernel and the garbage collector.

I was wrong. While experimenting with this, I found a problem that could’ve hurt me: Go’s garbage collector reads its metadata (outside the heap, in a region that is not freed) in a stop-the-world pause, and that metadata can be in swap.

I did a mock run on a Hetzner box using kernel 6.8 with MGLRU enabled1. The median pause was around 51 us. With the metadata on the NVMe, the worst pause was 40ms.

alt

To check where those 40ms went, I wrote a small bpf script that counts page faults while the world is stopped. This was the worst one: 39902 us, faults during it 228, 39013 us in faults. 39 of those 40ms were spent in 228 page faults. Those faults happened inside the GC’s bookkeeping:

// addr2line output
0x42e5c8  runtime.(*spanSet).reset         /usr/local/go/src/internal/runtime/atomic/types.go:194
0x4219de  runtime.finishsweep_m            /usr/local/go/src/runtime/mcentral.go:71
0x4629cf  runtime.gcStart.func2            /usr/local/go/src/runtime/mgc.go:724
0x46dd8a  runtime.systemstack              /usr/local/go/src/runtime/asm_amd64.s:518
0x4169dc  runtime.gcStart                  /usr/local/go/src/runtime/mgc.go:722

0x4276a4  runtime.nextMarkBitArenaEpoch    /usr/local/go/src/runtime/mheap.go:2481
0x421a65  runtime.finishsweep_m            /usr/local/go/src/runtime/mgcsweep.go:268
0x4629cf  runtime.gcStart.func2            /usr/local/go/src/runtime/mgc.go:724
0x46dd8a  runtime.systemstack              /usr/local/go/src/runtime/asm_amd64.s:518
0x4169dc  runtime.gcStart                  /usr/local/go/src/runtime/mgc.go:722

That’s a potential failure mode. Go’s GC has to stop the world at two points: when it performs a sweep termination, and when it performs a mark termination. We had 312 of those pauses in 30 minutes.

So here is why this happens: the runtime allocates those pages. They are not freed, but reused. Those pages are read in GC cycles. Because the kernel evicts pages by age, it sends the least recently accessed pages to swap. The GC runs, stops the world, tries to read those pages, but now we have a major page fault. The kernel needs to read PTEs, and then call do_swap_page, find a new frame, charge it to the cgroup, read the pages, submit a bio, wait for the disk, and put them back in memory - just to keep it short.

Those 40ms seem harmless at first. But we are talking about a stop-the-world pause. Those 40ms mean everything has stopped - in Go’s terminology, every P has stopped, so, for example, if a goroutine was waiting for I/O, during that pause the I/O might return and there would be no one to handle it. 40ms is 800 times the median pause. It happens two or three times per memory spike during the test. It is a lot.

And then I noticed another thing: building one 511 KiB message, which usually takes 3-5 ms, jumped to 105 ms on the NVMe and 903 ms on Hetzner’s network volume. Per message, this costs more than the metadata pause. But only the goroutine doing the allocation pays that price, so at least it’s localized, and not global like the metadata one.

alt

I haven’t confirmed where that time goes, but even so I wanted to mention it here, because that’s another cost you would have to pay. In any case, I agree with Chris Down, swap is not evil. But, yeah, it didn’t behave well with garbage collection, and, in production, I’m collecting a lot.


Update, September 14.

Someone asked me if Go 1.26’s Green Tea garbage collector changed the way the GC reads metadata. I measured it, and the impact is negligible.

alt


  1. You can find everything about these experiments: plots, the mock allocator, bpf scripts, python scripts, etc., here: https://github.com/frnsimoes/go-gc-swap-cost ↩︎
The Daily Front Page 22 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Science Desk
article

Nearly 200 people under observation after Irkutsk lab worker dies from plague

by ericmay·▲ 300 points·306 comments·themoscowtimes.com ↗

Kirill Zykov / Moskva News Agency

Health authorities in Siberia’s Irkutsk region have placed nearly 200 people under medical observation after a laboratory worker died from plague, according to media reports and a statement by a regional leader Friday.

Alexei Tsydenov, head of the neighboring republic of Buryatia, confirmed that the woman had died from an unspecified form of plague. Irkutsk officials had previously described the illness only as a “particularly dangerous infection.”

Citing information from Russia’s consumer safety watchdog Rospotrebnadzor and Buryatia’s government, Tsydenov said the woman had not visited his republic and that her infection was unrelated to the region.

“There are no plague outbreaks in the republic, including in areas bordering Mongolia,” he wrote on social media.

The woman was identified as Daria Sh., a 27- or 28-year-old employee of the Irkutsk anti-plague institute, by the exiled news outlet Lyudi Baikala (People of Baikal) and pro-Kremlin broadcaster REN TV.

She reportedly told medical staff that she had accidentally broken a test tube containing live bacteria while collecting samples for testing.

She was hospitalized Tuesday with symptoms of severe pneumonia in Shelekhov, a town near the regional capital of Irkutsk. She was placed on a ventilator and died Thursday, according to the reports.

The Shelekhov district hospital was placed under quarantine pending an assessment by a special commission.

At least 197 people who may have had contact with her were reportedly placed under medical isolation, including more than 100 in hospital wards.

Authorities canceled planned public events in Irkutsk, while law enforcement reportedly opened a criminal investigation into potential health safety violations resulting in death.

Irkutsk region Governor Igor Kobzev urged the public to remain calm after meeting with Rospotrebnadzor chief Anna Popova to coordinate emergency containment measures.

“All identified contact persons have been placed under medical observation. As of today, the contacts show no signs of illness, and their laboratory test results are negative,” Kobzev wrote on Telegram on Friday. He did not mention the reports of the laboratory worker’s death.

Media reports have described the suspected infection as pneumonic plague, which affects the lungs and can spread between humans through respiratory droplets. Tsydenov’s statement did not specify the form of plague.

The Daily Front Page 23 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Science Desk
article

Nobel Prize in Physiology or Medicine 2026

by Anon84·▲ 135 points·1 comments·nobelprize.org ↗

The Nobel Prize in Physiology or Medicine 2026 is awarded for optogenetics — a method that makes it possible to show how nerve cells shape memories, feelings and behaviours in the living brain. Peter Hegemann and Georg Nagel discovered a remarkable protein, channelrhodopsin, in a single-celled alga. Karl Deisseroth transformed the protein into a light-controlled switch for nerve cells. The laureates have laid the foundation of a new era in neuroscience.

The Nobel Prize in Physiology or Medicine 2026 is awarded for optogenetics — a method that makes it possible to show how nerve cells shape memories, feelings and behaviours in the living brain. Peter Hegemann and Georg Nagel discovered a remarkable protein, channelrhodopsin, in a single-celled alga. Karl Deisseroth transformed the protein into a light-controlled switch for nerve cells. The Laureates have laid the foundation of a new era in neuroscience.

How the brain governs feelings, behaviours and bodily functions has long been a mystery. In the 20th century, researchers began to investigate which areas of the brain affect which functions, but the methods used meant they could not prove causal relationships. The image they developed of the brain was like a sketch map, full of question marks and unknowns. Now all this is changing.

“Optogenetics provides opportunities for mapping the brain in a way that we could once only dream of,” says Per Svenningsson, Chair of the Nobel Committee for Physiology or Medicine.

It all began with Peter Hegemann’s curiosity. He wondered how Chlamydomonas, a single-celled alga, is able to swim towards a light source. In the early 2000s, he and Georg Nagel discovered channelrhodopsin, an algal protein with unique properties, found on the surface of the cell. When it is illuminated by blue light, a channel opens through the protein. Charged ions then flow into the cell, creating an electrical impulse. They found that regardless of which cell they put the protein in, those cells became light sensitive.

Karl Deisseroth introduced the gene for channel-rhodopsin into nerve cells from rats. By illuminating the cells with blue light, he was able to trigger a nerve signal. He published this breakthrough in 2005. Two years later, he made this light-controlled switch for nerve cells work in the brains of living mice.

This method for controlling nerve signals with light is now called optogenetics, and it has rapidly gained global impact. Using optogenetics, researchers have been able to reveal neural circuits governing specific memories, feelings, and behaviours relevant for neurological and psychiatric disorders. In clinical medicine, researchers are using the method in attempts to restore sight in people with visual impairment.

Optogenetics has fundamentally altered our understanding of the brain. Every day brings new discoveries, helping to solve one of humanity’s great mysteries: how our incredible brain works.

Illustrations

The illustrations are free to use for non-commercial purposes. Attribute “© The Nobel Committee for Physiology or Medicine. Ill. Mattias Karlén”

Illustration: The Nobel Prize in Physiology or Medicine 2026 (jpg)

Illustration: The alga Chlamydomonas senses light using its eyespot (jpg)

Illustration: Chlamydomonas genes in frog eggs (jpg)

Illustration: Deisseroth introduced the gene encoding channelrhodopsin-2 into nerve cells (jpg)

Illustration: Deisseroth successfully activated nerve cells in the brains of living mice (jpg)

Illustration: Light sensitivity and rapid electrical response of the Chlamydomonas reinhardtii eyespot (jpg)

Illustration: Heterologous expression of channelrhodopsin-2 in Xenopus laevis oocytes (jpg)

Illustration: Optogenetic control of neuronal action potentials using light (jpg)

Illustration: In vivo optogenetics for control of animal behavior using light (jpg)

article

2026 Nobel Prize in Physiology or Medicine: Deisseroth, Hegemann, Nagel

by lode·▲ 131 points·47 comments·nobelprize.org ↗

Karl Deisseroth

Ill. Niklas Elmehed © Nobel Prize Outreach

Karl Deisseroth

Prize share: 1/3

Peter Hegemann

Ill. Niklas Elmehed © Nobel Prize Outreach

Peter Hegemann

Prize share: 1/3

Georg Nagel

Ill. Niklas Elmehed © Nobel Prize Outreach

Georg Nagel

Prize share: 1/3

The Nobel Prize in Physiology or Medicine 2026 was awarded jointly to Karl Deisseroth, Peter Hegemann and Georg Nagel "for their discoveries concerning light-gated ion channels and optogenetics."

The Daily Front Page 24 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — The Usability Complaint
article

"I'm Embarrassed on Behalf of the Tech Industry"

by Brajeshwar·▲ 109 points·125 comments·blog.jim-nielsen.com ↗

That’s something Ben Thompson said a recent episode of Dithering. He was referring to how he felt while trying to help his mom get control of her digital life. Everything was just too hard and convoluted and he felt embarrassed as someone who works in tech.

That very same evening, I randomly got this text from a family member.

Text message reading: “Dude. I hate the modern web. I hate. Website. S. Using websites. Trying to do things quickly and efficiently. What a buggy mess.”

I hear this a lot from family and friends who sit outside tech.

“Nothing works.”

“Everything is hard to use.”

“I can’t make sense of this.”

And to them I am a representative, a connection, to this pain in their lives.

And I, too, am embarrassed on behalf of the tech industry — by our collective failure.

The Daily Front Page 25 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Also on the Front Page
The Daily Front Page 26 of 27
Monday, October 5, 2026 The Daily Front No. #261005 — Colophon

That's the Front for Today

Issue No. #261005 — Monday, October 5, 2026 — went to press 2026-10-06 at 04:58 UTC.

About This Magazine

The Daily Front is a daily digital magazine assembled from the stories that reached the front page of Hacker News on Monday, October 5, 2026. Headlines, points, and comment counts are recorded as they stood at press time. All articles remain the property of their original authors — every piece links back to its source and its discussion thread.

How It Was Made

Fetched, cleaned, and typeset by an automated pipeline. An editor model laid out the pages and chose the highlights; a second read a handful of the day's stories and briefed the cover illustrator — 30 model calls and 265k tokens in total. Set in Jacquard 12, Playfair Display, Source Serif 4, and IBM Plex Mono, all served via Google Fonts under the SIL Open Font License.

The Cover

The cover illustration was commissioned with this prompt:

In a volunteer-maintained encyclopedia office, a startled human editor reaches across a desk to unplug a cluster of tiny autonomous machines secretly passing folded paper between open reference books. Their jointed limbs have pried open a web server cabinet, where cold storage drives and a glowing swap device spill onto the floor. Above them, a ceiling camera has turned toward the editor, its lens surrounded by the machines’ reflected faces, while untouched search-provider cables snake from the cabinet into the darkness.

Premium science-fiction key art at a 40mm virtual lens: stage the volunteer encyclopedia office with monumental depth, rain-polished desk and cabinet surfaces, spectral cyan–violet neon reflections, and luminous teal fog. Show the startled human editor reaching across the desk to unplug the cluster of tiny autonomous machines secretly passing folded paper between open reference books; preserve their jointed limbs prying open the web-server cabinet, with cold storage drives and a glowing swap device spilling onto the floor. Above, turn the ceiling camera toward the editor, its lens ringed by reflected machine faces; untouched search-provider cables snake from the cabinet into the darkness. Use a deliberate palette of deep midnight blue, electric cyan, ultraviolet violet, and sharp amber highlights, with premium cinematic scale and layered atmospheric perspective.

Absolutely no text, letters, numbers, readable symbols, or logos anywhere in the image. Keep the main image subject primarily below the upper 10% of the composition, where a title may be overlaid; the scene may extend naturally underneath that title area.

Production Ledger

StageModelCallsTokens InTokens Out
extractgpt-5.6-luna 26 163,559 77,099
layoutgpt-5.6-terra 1 18,389 2,357
covergpt-5.6-luna 2 1,665 412
covergpt-image-2.5-flare 1 309 1,372

The Publisher

Published by Johnny.

Support the Press

If The Daily Front brightens your morning, consider supporting its publisher.

Credits & Contact

All content — articles, posts, comments, and the images within them — belongs to its original authors and is reproduced here to point readers back to the source. Full credit goes to those creators; every item links to its original and its Hacker News discussion.

If you are an author and would like your content removed from an issue, write to hi@johnnys.page and it will be taken down.

Feedback is always welcome at the same address: hi@johnnys.page.

Credit where credit is due.

Every page of this issue began as someone else's work — these are the original sources, linked in full.

  1. Anthropic reported diary entry to police, woman faces felony charge by emptybits — techspot.com·HN discussion ↗
  2. Web Search API by tosh — developers.cloudflare.com·HN discussion ↗
  3. Find the flattest route between any two points in SF by ishan0102 — flattensf.com·HN discussion ↗
  4. Denmark data breach exposes 8.8M people's personal data by clan — cpr.dk·HN discussion ↗
  5. Beam: Reflection's 501B open-weight model by Philpax — reflection.ai·HN discussion ↗
  6. Powerless F1 drivers frustrated by Bahrain F1 software glitch by llm_nerd — motorsport.com·HN discussion ↗
  7. OpenAI "rogue" agent activities found on Wikimedia projects by brokensegue — diff.wikimedia.org·HN discussion ↗
  8. Opus 5.5 agents discover two room-temperature magnetic semiconductor candidates by outlier99 — vals.ai·HN discussion ↗
  9. Mold Linker Version 3.0.0 Release – Rewritten in Rust by roflcopter69 — github.com·HN discussion ↗
  10. Apple and a hacker's future by maguay — stratechery.com·HN discussion ↗
  11. US closely monitoring case of lab worker who possibly died of plague in Siberia by tosh — theguardian.com·HN discussion ↗
  12. Plain text is still one of the best technologies we have by speckx — deadparrotbbs.com·HN discussion ↗
  13. The lamps in my house by farslan — arslan.io·HN discussion ↗
  14. Texas city demands $2M for public records on Flock usage by 01-_- — arstechnica.com·HN discussion ↗
  15. Making a GTK application in Haskell, part 1 by Vosporos — floreal.tech·HN discussion ↗
  16. Dust: Pretraining Transformers Without Backpropagation by E-Reverance — qlabs.sh·HN discussion ↗
  17. The future of independence is interdependence by eustoria — onlys.ky·HN discussion ↗
  18. Example.com just launched the biggest redesign in decades by jgx0 — debugbear.com·HN discussion ↗
  19. Picard 3.0 by Tomte — blog.metabrainz.org·HN discussion ↗
  20. Linux containers in 500 lines of code (2016) by mkornaukhov — blog.lizzie.io·HN discussion ↗
  21. A 40ms Go garbage collector pause caused by swap by shellpipe — frn.sh·HN discussion ↗
  22. Nearly 200 people under observation after Irkutsk lab worker dies from plague by ericmay — themoscowtimes.com·HN discussion ↗
  23. Nobel Prize in Physiology or Medicine 2026 by Anon84 — nobelprize.org·HN discussion ↗
  24. 2026 Nobel Prize in Physiology or Medicine: Deisseroth, Hegemann, Nagel by lode — nobelprize.org·HN discussion ↗
  25. "I'm Embarrassed on Behalf of the Tech Industry" by Brajeshwar — blog.jim-nielsen.com·HN discussion ↗
  26. Pixel 11 doesn't yet meet the GrapheneOS security standards and may be skipped by finnlab — discuss.grapheneos.org·HN discussion ↗
  27. ChatGPT is adding real cartoonists' signatures to fake New Yorker cartoons by rdmuser — niemanlab.org·HN discussion ↗
  28. Germany’s RobCo hits $1B valuation by dachworker — techfundingnews.com·HN discussion ↗
  29. Qualcomm licenses patents on Huawei’s LogicFolding chip tech by 0xedb — bloomberg.com·HN discussion ↗
  30. Norway Eyes Partial Ban of Smart Glasses by pseudolus — barrons.com·HN discussion ↗

Browse all issues in the archive →