📰 NewsMonitor

Nieman Journalism Lab: Twitter/X Punishes Accounts That Post Links

Laura Hazard Owen, writing for Nieman Journalism Lab back in April: I used Claude to help me scrape the 200 most recent tweets from 18 large publishers’ X accounts and track the engagement (likes + comments + retweets) on each. Six of those publishers have paywalls: Bloomberg, CNN, Forbes, The New York Times, The Wall Street Journal, and The Washington Post. Nine don’t: Al Jazeera English, AP, BBC, Breitbart News, CBS News, Daily Wire, Fox News, NBC News, and Reuters. The last three accounts I looked at — Leading Report, unusual_whales, and Globe Eye News — are not news publishers, but aggregate breaking news in tweets without links. (Here, for example, is an example of a Leading Report tweet: “BREAKING: Iran has halted direct talks with the US, per WSJ.” They’re sometimes referred to as engagement-maxing accounts. These charts make it pretty clear that links in tweets hurt engagement. The connection was so apparent in my analysis that a graph including all 18 publishers is almost unreadable: The traditional, link-loving publishers are clustered in the bottom left corner (lots of links, little engagement) in a nearly indistinguishable mass of bubbles, no matter how large their followings are. Musk’s Twitter/X is not an aggregator for news. It’s a walled garden. But the type of garden where you need to keep your eyes open and your hand on your wallet. Sometimes it’s fun to visit a seedy neighborhood. But let’s not pretend it isn’t a seedy neighborhood just because, long ago, it used to be nice.  ★

Elon Musk’s X Is a Freak Show

Nate Silver, back in April, under the headline “Social Media Is Turning Into a Freak Show”, where by “social media” he mostly discusses Twitter/X: But what does that remaining traffic consist of? I recently came across a bubble chart depicting the Twitter accounts that had received the most “engagement” in February 2026. It was depressing: most of the top accounts were extremely low-quality and highly partisan. I hadn’t even heard of many of them and only follow a handful of the top accounts. So I tracked down the original data myself and, with help from Claude, made my own improved version of the chart. Here, voilà, are the Twitter accounts with the most engagement so far in 2026:

It’s not hard to notice that Twitter has become extremely right-leaning. But I’d argue there’s an equally important trend: the top accounts are of incredibly low quality. Elon, with the algorithmic boost he built in for himself, is at the eye of the storm, of course. But “Catturd” literally gets far more engagement than the New York Times, for instance. There’s a common argument from proponents of the Musk-era X that the only problem is that left-leaning people have abandoned the platform. That the X algorithm is a contest and if only right-leaning accounts are playing, of course they’re winning. This is nonsense. The whole thing is rigged. Elon Musk’s outsized prominence as the most-engaged-with account is proof of that. Twitter existed for 16 years before Musk bought it. He wasn’t even close to the biggest account during that era. Then he bought it. Now his account is the biggest. As Silver’s data analysis shows, Musk’s X is not just dominated by right-wing accounts, it’s dominated by “who the hell is that?” right-wing slop accounts. The only way not to lose a rigged game is to refuse to play. X is still a thing. A lot of people, companies, and organizations still post there — treat it like their blogs — exclusively. I still wind up linking to posts on X because that’s where they are. That’s a whole separate discussion. But anyone who’s trying to “compete” there with subject matter that is even vaguely political has no chance of success unless what they’re posting is what Elon Musk wants to see promoted. It’s not like his thumb is on the scale, it’s like an anvil is on the scale. The conundrum is that there are still a lot interesting people posting interesting things there.  ★

Premium: The Hater's Guide To The AI Bubble 3.0

Last year I wrote one of my favourite pieces ever — The Hater’s Guide To The AI Bubble — and followed it up with The Hater’s Guide To The AI Bubble Volume 2 several months later. Sadly, I’ve realized “volume” is a

Checking in on Perplexity

Yours truly, last August: I can’t see why Apple would want to get involved with a company like this though. Gurman’s report makes it sound like his sources are inside Apple, but man, this “Apple + Perplexity” thing feels more like something Perplexity would be seeding than one that Apple executives would be leaking. Perplexity is still occasionally in the news (often not in good ways), but it seems to me they’ve slipped into the “afterthought” tier of AI startups — which is exactly why they started leaning into clownish stunts last year. Everyone who previously suggested Apple should — or even might — buy them has gone silent.  ★

Install-script allowlists

In most package managers a dependency’s install-time code runs by default the moment you install it: an npm postinstall, a Setuptools setup.py, a CPAN Makefile.PL, an RPM scriptlet, a Conda post-link, a Debian postinst. A handful require explicit per-package opt-in before any of that code runs, usually called an allowlist or a trusted-dependencies list depending on the tool. Per-package opt-in lists name which dependencies may run their install code: npm, pnpm, Bun, Deno, and Composer plugins all work this way. Global sandboxes (opam, Swift Package Manager, Nix, Guix, Portage) take a different shape, executing everything but constraining what that execution can reach. Identity and signature verification (RubyGems trust policies, Gradle dependency verification, NuGet trustedSigners, apt-secure) gates which artifacts get installed in the first place by who signed them, with no bearing on what their code subsequently does. An npm postinstall, a setup.py, a Makefile.PL or an RPM scriptlet fires during fetch or unpack. A Cargo build.rs or a Zig build.zig runs when the project is compiled, which on a fresh build is functionally the next step but is structurally distinct. JVM build files (Gradle’s Groovy or Kotlin, Maven’s plugin goal invocations, SBT’s Scala) execute earlier still, before any project source touches the compiler. JavaScript npm shipped per-package allowlists in 11.10.0 (February 2026) via an allowScripts field in package.json, managed by npm approve-scripts and npm deny-scripts, with entries pinned to a specific version (pkg@1.2.3: true) by default and denials written name-only. Behaviour in 11.x is advisory: scripts still execute, an end-of-install summary names anything unreviewed, and a hard block is signposted for npm 12. The similarly-named npm trust command added in the same release is for OIDC trusted publishing rather than script execution. pnpm v10 (January 2025) blocked install scripts by default, reading the allowlist from onlyBuiltDependencies / neverBuiltDependencies in package.json or pnpm-workspace.yaml. v11 consolidated those into a single allowBuilds map, with dangerouslyAllowAllBuilds as the escape hatch. The companion pnpm approve-builds (added in 10.1.0) is an interactive picker that accepts --all for CI and from v11 takes positional arguments like pnpm approve-builds esbuild fsevents !core-js. Packages not on the list fail the install when strictDepBuilds is true (the v11 default) and warn otherwise. Yarn Classic (v1) has no native per-package mechanism, only the global --ignore-scripts flag, with yarnpkg/yarn#7338 tracking the feature request. The @lavamoat/allow-scripts project retrofits one across Yarn v1.22+, Yarn Berry v3+, npm v8+, and pnpm: it disables scripts at the package-manager level then drives execution from a lavamoat.allowScripts map in package.json. Yarn Berry (v2+) is declarative: set enableScripts: false globally in .yarnrc.yml, then opt packages back in via dependenciesMeta..built: true. No interactive approval command exists, and workspace packages always run their own scripts regardless of the global setting. Bun blocks install scripts for dependencies by default and ships a built-in default allowlist of well-known packages (esbuild, fsevents, others) auto-trusted only when sourced from the npm registry. The trustedDependencies array in package.json overrides that list, so opting a single package in drops the default-trusted set entirely. Trust is added by name via bun pm trust or bun add --trust (which pulls in the package’s transitive deps), and bun pm untrusted lists packages with install scripts that haven’t been granted trust. Deno never runs npm lifecycle scripts unless explicitly approved, via the --allow-scripts= flag on deno install and deno cache (Deno 1.45/1.46, mid-2024) that accepts comma-separated specifiers like npm:sqlite3,npm:esbuild@0.21.5. Deno 2.6 (December 2025) added deno approve-scripts, which persists per-package decisions into deno.json. Packages without approval have their scripts skipped at install time and listed in an end-of-install warning so they can be reviewed before the next run. PHP Composer’s top-level scripts field carries lifecycle hooks tied to events like pre-install-cmd and post-update-cmd, but only the root package’s scripts run during install: a dependency’s scripts never execute in the parent project, unlike npm’s postinstall. Plugins are the actual transitive execution surface, and the allow-plugins configuration key (Composer 2.2, 2021-12-22) made plugin activation explicit per package. The key takes "vendor/package": true|false entries with wildcard support ("vendor/": true), defaults to {}, and prompts interactively for unlisted plugins while persisting the answer. Non-interactive runs (--no-interaction, CI) error rather than silently skipping, so an install that succeeded locally fails in CI until the plugin is on the list. Python Python wheels conventionally have no install-time hooks, so for Python the install-script question becomes whether a package may execute PEP 517 build backend code locally when the resolver picks an sdist over a prebuilt wheel. Pip has no per-package allowlist for that. pypa/pip#425, opened in 2012 under the title “pip should not execute arbitrary code from the Internet”, captures the historical position. The closest controls are global: pip install --only-binary :all: refuses source distributions entirely, with --no-binary available as a per-package exception. Secure installs recommends pairing --only-binary :all: with --require-hashes. The inverse --only-binary-except= is tracked at pypa/pip#10724. pypa/pip#13079 (fixed in pip 25.0) showed that wheels aren’t inert in practice: a malicious wheel could overwrite pip’s own internal modules and execute code at the tail of pip install. uv has per-package source-build controls via a set of settings that pair global and per-package toggles: no-build and no-build-package refuse sdists, no-binary and no-binary-package force source builds, no-build-isolation and no-build-isolation-package toggle PEP 517 build isolation. The combination amounts to a per-package allowlist for which packages may execute build backend code locally. astral-sh/uv#11682 asked for only-binary to gain a persistent project-level form alongside the existing CLI flag. Poetry exposes installer.only-binary (Poetry 2.0.0+) and installer.no-binary as comma-separated package lists or the special values :all: / :none:. Combining installer.only-binary = ":all:" with installer.no-binary = "pkgA" produces a per-package source-build allowlist by composition, since the docs state that explicit package names override :all:. PDM has --no-isolation for build isolation but no no-binary-package equivalent in the CLI reference. Pipenv has neither natively. The documented workaround is --extra-pip-args="--only-binary=:all:" or setting PIP_NO_BINARY / PIP_ONLY_BINARY for pip to read directly. Conda packages can ship pre-link, post-link, and pre-unlink shell scripts that run on the user’s machine during install and uninstall. The link-scripts documentation advises authors to avoid them but documents no allowlist, no .condarc toggle, and no CLI flag to disable them. Conda’s security configuration knobs (safety_checks, extra_safety_checks, signing_metadata_url_base, channel allowlist/denylist) cover artifact integrity and channel provenance, not per-package script execution. Mamba and micromamba reimplement the install model and inherit the same gap. The indirect mitigation is that noarch: python packages are required by policy not to ship link scripts, so restricting yourself to noarch: python deps avoids the surface for pure-Python work. Ruby RubyGems and Bundler have no per-gem allowlist for install-time code execution. Gems with ext//extconf.rb run arbitrary Ruby at install time to configure native extension builds, and the same applies to Rakefile / mkrf_conf variants declared under a gem’s extensions list. The signing and trust-policy mechanism at guides.rubygems.org/security (LowSecurity, MediumSecurity, HighSecurity) checks who published a gem, not whether it may run install-time code. bundle config build. -- --with-foo passes arguments to native builds without gating whether they happen. Perl CPAN distributions ship a Makefile.PL (ExtUtils::MakeMaker) or Build.PL (Module::Build) which are ordinary Perl scripts executed at install time by cpan, cpanm, or cpm. There is no per-distribution capability gate, no first-time prompt, and no equivalent of allow-plugins. CPAN.pm exposes makepl_arg, mbuildpl_arg, and prerequisites_policy knobs for tuning how Makefile.PL is invoked and how dependencies are resolved, none of which gate whether the code runs. Systems languages Cargo runs build.rs and proc-macros as ordinary host-native Rust code during every cargo build, test, run, and install against the affected crates. Proc-macros execute inside the rustc process during compilation, so any procedural-macro dependency runs its code on every build. There is no global flag to disable proc-macros and no sandbox around the script process. A crate’s own Cargo.toml can set build = false to suppress its own build script, but consumers cannot disable a dependency’s build.rs. The long-running tracking issues are rust-lang/cargo#5720 (sandbox/jail build scripts, July 2018) and rust-lang/cargo#13681 (build script allowlist mode, April 2024), plus the compiler-team MCP proposing an isolating runtime shipped via rustup, none of which has landed. cargo-vet and cargo-crev flag custom-build crates for reviewer attention; neither prevents execution. Go modules don’t run downloaded code beyond compiling it, with go run, go test, and go generate documented as the explicit exceptions in Russ Cox’s “Command PATH security in Go”. There is no per-module trust mechanism because nothing third-party runs in the first place. The cgo #cgo CFLAGS: and LDFLAGS: directives have been the escape hatch. CVE-2018-6574, CVE-2024-24787, and #42559 were each mitigated by extending a hard-coded allowlist of permitted compiler/linker flags in the toolchain. CVE-2023-39323 addressed an adjacent surface by restricting //line directives in cgo-generated files. No per-module grant was added in any of these cases. Swift Package Manager runs both Package.swift manifest evaluation and package plugins inside a sandbox (sandbox-exec on macOS) with no network access and writes restricted to a per-plugin temporary directory by default. Plugins that need more declare permissions in their target definition using PluginPermission: writeToPackageDirectory(reason:) and allowNetworkConnections(scope:reason:) with scope none, local(ports:), all(ports:), docker, or unixDomainSocket. The user is prompted on a TTY (PR #5483) or must pass --allow-writing-to-package-directory / --allow-network-connections non-interactively, with decisions scoped per package. The permission-grant model covers command plugins but not build tool plugins. Build tool plugins still run inside the sandbox by default but cannot declare or be granted writeToPackageDirectory / allowNetworkConnections. The build-tool sandbox permissions pitch tracks the extension to that surface. Zig’s build.zig is arbitrary Zig code compiled to a native host binary and executed by zig build, including for every transitive dependency pulled in by the package manager. There is no sandbox and no per-package gate. The proposal at ziglang/zig#14286 (open, labelled urgent) has no merged implementation yet. It would compile every build.zig to wasm32-wasi and emit the build graph as data for a separate build_runner to execute under whatever permissions are granted. JVM JVM dependencies are passive JARs that don’t execute on resolve or install. Build-time plugins are the execution surface. Maven has no built-in allowlist of which plugins may load. Plugin goals execute as ordinary Java during the build lifecycle. The Maven Enforcer plugin’s bannedPlugins and bannedDependencies rules are blocklists with includes carve-outs, so an allowlist has to be expressed as banning * and re-including specific GAVs. Core extensions declared in .mvn/extensions.xml load into Maven’s core classloader before the build starts, with no signature check or allowlist. Gradle’s build.gradle(.kts), settings.gradle(.kts), convention plugins, and applied plugins all execute arbitrary Kotlin/Groovy at configuration time, with no per-plugin code-execution allowlist. Dependency verification via verification-metadata.xml covers regular dependencies and plugins through checksum and PGP signature verification of artifact identity. That establishes who published the artifact, not what its code may do. Init scripts (-I, $GRADLE_USER_HOME/init.gradle(.kts), init.d/.init.gradle(.kts)) run unconditionally with no signature check. The configuration cache serialises the configured task graph for performance, not to restrict what plugin code may do. SBT plugins declared in project/plugins.sbt run at build configuration time with full JVM access. The official docs describe classloader-level encapsulation between plugins and build definitions as an authoring convenience, not a security boundary. There is no allowlist or signature verification analogous to Gradle’s verification-metadata.xml, and SBT inherits whatever artifact-verification posture the underlying Ivy or Coursier resolver provides. Leiningen and Mill take the same approach, with project.clj in Clojure and build.sc in Scala running as configuration-time programs and neither providing a per-plugin allowlist. Bazel sits at the opposite end of the JVM build-tool spectrum. BUILD files and .bzl extensions are written in Starlark, a Python dialect with no clock access, no recursion, no mutable global state, and no filesystem or network calls outside declared inputs. Build actions run in a sandbox that sees only what the rule declares. The escape hatches exist (repository_rule for fetching, genrule for shell, custom toolchains), but the default posture is that a BUILD file cannot observe its host, and the per-action sandbox covers what would otherwise need an allowlist. .NET Under PackageReference (NuGet 4.0+ and the default for SDK-style projects), the historical install.ps1 and uninstall.ps1 PowerShell scripts no longer execute on install or uninstall, per the migration guide. The replacement execution surface is MSBuild build/, buildMultiTargeting/, and buildTransitive/ .props and .targets files, auto-imported into the consumer’s build through NuGet-generated {projectName}.nuget.g.props and .nuget.g.targets. buildTransitive lets a transitive dependency contribute targets to your project without you naming it as a direct dependency. There is no per-package allowlist for MSBuild target imports. The configuration in nuget.config controls which signed packages are accepted by signer identity, without bearing on what their MSBuild contributions then do. Other languages Hex/Mix (Elixir) evaluates each dependency’s mix.exs and runs its compile task on mix deps.compile, with no per-package allowlist and no separate install-script field beyond compilation. Rebar3 (Erlang) supports pre_hooks, post_hooks, provider_hooks and plugins loaded from Hex, all of which execute when their declaring dependency is built, again without any allowlist. Cabal and Stack (Haskell) historically run arbitrary Setup.hs programs for packages with build-type: Custom. The recent build-type: Hooks in Cabal 3.14 (2024) replaces wholesale Setup replacement with a fixed set of named hook points, narrowing the surface without introducing an allowlist. Opam (OCaml) wraps every package’s build: and install: commands with sandbox.sh (opam 2.0, 2018), using bubblewrap on Linux and sandbox-exec on macOS. The build phase can write to the build directory and /tmp but sees the switch as read-only; the install phase can write to the switch. Network access is denied throughout. The sandbox is global rather than per-package, and opam init --disable-sandboxing turns it off. Pub (Dart/Flutter) historically ran no dependency code on resolution. The hook/build.dart mechanism started as an experiment in Dart 3.2 behind --enable-experiment=native-assets and stabilised in Dart 3.10. The design is advertised as “semi-hermetic” for reproducibility, not for adversarial isolation. LuaRocks rockspecs can declare command, make, cmake, or builtin build backends, with the command backend executing arbitrary shell during luarocks install and no allowlist over which rocks may do so. Nimble (Nim) supports before and after template hooks in .nimble NimScript files, with exec of external processes as the documented escape hatch from NimScript’s own FFI restrictions. zef (Raku) runs a Build.rakumod or a builder module declared in META6.json unconditionally during the build phase. The --/build flag disables the build phase globally; no per-distribution gate is documented. Crystal Shards supports a postinstall field in shard.yml with a global --skip-postinstall flag as the only opt-out. The community forum thread “postinstall considered harmful” covers the case for changing this. Julia Pkg runs deps/build.jl on first install of each dependency, with the modern alternative being BinaryBuilder-produced _jll packages referenced by hash, although build.jl remains supported. R source packages on CRAN run a configure Bourne shell script (and configure.win on Windows) before anything else, plus arbitrary code in R/zzz.R’s .onLoad and .onAttach. CRAN’s mitigation is editorial review and pre-built Windows/macOS binaries from the build farm, with no per-package mechanism. CocoaPods displays a per-install warning the first time a Podfile pulls in a pod with script_phase build phases, plus on every update where the pod still contains them, without persisting a stored allowlist. Carthage clones each dependency’s repo and invokes xcodebuild against its shared schemes, which executes any Run Script build phases declared in the dependency’s .xcodeproj without warning or allowlist. C/C++ Conan recipes are full Python modules whose source(), build(), package(), and package_info() methods run in the host Python process during conan install and conan create. There is no sandbox or allowlist; curation of the ConanCenter index is the trust boundary. vcpkg ports are portfile.cmake files interpreted by CMake’s script mode and able to call execute_process and vcpkg_execute_build_process, with no per-port allowlist or sandbox per the ports documentation. Spack package.py files are arbitrary Python with install() methods and build phases that run during spack install. Spack’s security framing covers download integrity (checksummed tarballs, pinned git commits), not per-recipe capability. OS distributions On dpkg/apt, RPM/dnf, pacman, and Alpine’s apk, install-time maintainer scripts (preinst/postinst/prerm/postrm for dpkg, %pre/%post/%preun/%postun for RPM, .INSTALL for pacman, $pkgname.{pre,post}-install plus .{pre,post}-upgrade, .{pre,post}-deinstall, and .trigger for apk) run as root with no sandbox, no chroot, and no seccomp filter. The trust model is the archive itself, with apt-secure(8) gating which packages enter the install pipeline via repository GPG signing. There is no per-package allowlist or opt-in flag, and the Debian wiki’s UntrustedDebs page treats installing a .deb from outside the trusted archive as effectively giving the package author root. The pacman official repositories follow the same archive-curation model. The AUR exposes raw PKGBUILDs and .INSTALL files to users for review, with AUR helpers (yay, paru, pikaur, others compared in the helpers table) differing on whether they prompt for a diff of PKGBUILDs before sourcing them. Nix and Guix run every derivation’s builder inside a chroot with a fresh PID/network/mount namespace, an unprivileged build user (Nix’s nixbld pool, Guix’s guixbuild pool), and no network access except for fixed-output derivations whose output hash is declared up front. The model is documented in the Nix configuration reference and the Guix Build Environment Setup chapter. Every builder runs inside the box, with fixed-output derivations and the small trusted-users set as the remaining trust surface. CVE-2024-27297 was a fixed-output-derivation sandbox bypass affecting both Nix and Guix. Portage (Gentoo) enables FEATURES="sandbox" by default, an LD_PRELOAD shim that intercepts filesystem syscalls and blocks writes outside permitted build directories. userpriv runs ebuild phases as the portage user, and usersandbox combines the two. The mechanism is LD_PRELOAD-based, so static binaries and direct syscalls bypass it, as documented on the Gentoo wiki’s Sandbox (Portage) page. Trust still flows from the curated Portage tree’s signed Manifest files, with no per-ebuild capability grant. Overlays sit explicitly outside that boundary. Userland package managers Homebrew, MacPorts, Scoop, and Chocolatey locate trust at the repository (tap, ports tree, bucket) level rather than per-package: tapping a repository or adding a bucket grants it the same trust as the core repository, and individual formulae, ports, or manifests have no per-package allowlist. Homebrew’s security policy makes the tap-level boundary explicit. MacPorts signs the ports tarball (GHSA-2j38-pjh8-wfxw, disclosed December 2024, covered an rsync filter bypass that let a malicious mirror deliver unsigned Portfiles past the signed-archive boundary and trigger Tcl execution during portindex). Scoop bakes a known-bucket list into the client with per-manifest hash verification. Chocolatey adds human moderation of community submissions on top of optional package signing, with Trusted Packages bypassing manual review based on author track record. winget differs because its YAML manifests don’t include arbitrary install-time scripts. The supported InstallerType values are real installer formats (msi, msix, appx, exe, inno, nullsoft, wix, burn, portable, zip, font, msstore), and the manifest declares a SHA256 of the installer binary. winget validate checks manifest format; PR review on the winget-pkgs repo plus Azure Pipelines bot validation covers submission integrity, alongside an optional local SandboxTest.ps1 that authors can run to test a candidate inside Windows Sandbox before submitting. Version managers asdf plugins are Git repositories of shell scripts (bin/install, bin/list-all, others) that run as the user during asdf install, with no allowlist or sandbox: adding a plugin is functionally equivalent to running its bash. mise reduces the plugin surface by routing most tools through non-shell backends: mise discussion #4054 maps most tools to aqua, ubi, vfox, or core in the default registry, with asdf plugins forked under the mise-plugins GitHub org so commit access is controlled. mise trust and trusted_config_paths gate execution of [env], [hooks], and [tasks] blocks in project-level mise.toml files, prompting on first cd into a directory with an untrusted config and persisting the decision per file.

Some People Rooted for The Empire in ‘Star Wars’, Too

Ed Morrissey, writing for Hot Air, thinks Scott Pelley got what he deserved and Bari Weiss is doing a good job running CBS News: And Pelley forgot the Golden Rule: He who has the gold makes the rules. Instead, Pelley convinced himself of his own virtue and torched his own position — and if Bilton’s letter is accurate, in as mean-spirited and conceited a manner as possible. Pelley could have chosen a dignified resignation under protest, but instead pulled a power move in an attempt to intimidate Bilton, Weiss, and Ellison, only to discover that no one feared his absence. In fact, they’re probably happy to cut him loose. There’s always at least one person in these situations who thinks they’re untouchable. A wise executive knows to start by making an example of that person, and then see how many other people think they’re indispensable. It’s not as if TV news jobs are expanding these days, after all. Pelley’s going to find out the hard way that no one’s paying $5 million a year to emote into a camera from other people’s copy. It doesn’t even enter this man’s little mind that Pelley wasn’t concerned about his job, wasn’t concerned about his salary, but was concerned only with the integrity of the institution to which he’d committed decades of his career, and that he saw as his duty the need to stand up for his remaining and former colleagues. That Pelley himself has integrity. To the Trump lickspittles, everything is performative. They don’t just lack integrity, they don’t believe integrity is real. Katie Notopoulos: The Scott Pelley story to me is a lesson in how if you work hard enough in your career to get Fuck You Money, the real reward is the day you need to say it, you can.  ★

‘The Insider’

All this Sturm und Drang surrounding 60 Minutes has me thinking about a re-watch of The Insider, Michael Mann’s great 1999 movie. Letterboxd’s synopsis: “A research chemist comes under personal and professional attack when he decides to appear in a 60 Minutes exposé on Big Tobacco.” It’s a great movie, and feels apt AF at the moment. Here’s the original segment on 60 Minutes, which ran an entire half hour. What’s going on today is like if — instead of getting shady, threatening, and litigious — the tobacco companies had just purchased CBS, purged the staff at 60 Minutes, and hired a bunch of pro-cigarette stooges to replace them.  ★

‘Microsoft and OpenAI Broke Up — Now They’re Ready to Fight’

Hayden Field and Tom Warren, writing for The Verge (gift link) This year’s Build had the vibe of a freshly single divorcée posting a thirst trap on Instagram. “It’s always fun to be at developer conferences in times of great change,” Microsoft CEO Satya Nadella said onstage Tuesday, adding that events like this are about “coming to grips with the new opportunity.” AI chief Mustafa Suleyman, in an interview with The Verge, put it even more bluntly. “The goal is to prove that we can become one of the top four labs in the world,” Suleyman said. “There’s three labs that matter, Google DeepMind, OpenAI, and Anthropic. We are not one of them at the moment, and that’s always been my intention. It’s why I came here. I want to build the very best frontier models in the world, fully multimodal, and in order to do that, we have to prove that we can do everything that we need to from the ground up, and we’re not just going to take from others.” Refreshingly blunt. But hasn’t that been Microsoft’s plan for Bing since it was announced in 2009? I mean I guess you can say that Bing is one of the top four search engines in the world. Maybe you can even say it’s one of the top two. But it’s irrelevant and uncompetitive with Google Search.  ★

Lingon and Lingon Pro 10

Peter Borg: Lingon makes scheduling apps, scripts, shortcuts, and commands feel simple. Create a task in minutes, run it on a schedule, and stay in control. Lingon helps you run whatever you want whenever you want without living in Terminal. Schedule apps, scripts, shortcuts, and commands with a clear, friendly UI. Run tasks at specific times, on intervals or at login. Optional notifications make it easy to keep control. Two separate apps. Lingon is the simpler Mac App Store version and free to use, while Lingon Pro is the advanced one-time purchase with extra power. Lingon and Lingon Pro are great apps. I’ve been meaning to recommend them for a while. Back in 2023 I wrote about a problem I was having with Maestral, the incredible “works like Dropbox in the old days” open-source Dropbox client, where Maestral would just silently crash once in a while and I wouldn’t notice for a while. Then I would notice, manually re-launch Maestral, and have to wait while Maestral synced. Or, worse, I’d put a podcast recording in a shared folder and walk away from my computer, and my editor would never get the file because Maestral wasn’t running. My write-up described how I solved the problem with a Keyboard Maestro macro that runs once an hour — it checks if Maestral is running, and if it isn’t, launches it (and writes to a log, to satisfy my own curiosity). Borg wrote to me after I posted that and — very politely — explained that Lingon would make that much simpler. In addition to creating your own scripts and rules that run periodically, Lingon is great for inspecting all the login items and background agents on your system — whether they’re from Apple or third parties. Poking around at everything Google Gemini installed is what made me think to recommend Lingon today. At the very least you should install the free regular version. It’s just a great Mac utility from a great Mac developer. There’s nothing else like it.  ★

Remember When Chrome Went Bad on MacOS?

Loren Brichter, back in 2020: Short story: Google Chrome installs an updater called Keystone on your computer, which is bizarrely correlated to massive unexplained CPU usage in WindowServer (a system process)1, and made my whole computer slow even when Chrome wasn’t running. Deleting Chrome and Keystone made my computer way, way faster, all the time. Long story: I noticed my brand new 16” MacBook Pro started acting sluggishly doing even trivial things like scrolling. Activity Monitor showed nothing from Google using the CPU, but WindowServer was taking ~80%, which is abnormally high (it should use < 10% normally). Doing all the normal things (quitting apps, logging out other users, restarting, zapping PRAM/SMC, etc) did nothing, then I remembered I had installed Chrome a while back to test a website. I deleted Chrome, and noticed Keystone while deleting some of Chrome’s other preferences and caches. I deleted everything from Google I could find, restarted the computer, and it was like night-and-day. Everything was instantly and noticeably faster, and WindowServer CPU was well under 10% again. Not all Mac users, but many, found that just having Chrome installed slowed down their Macs dramatically. Completely uninstalling Chrome — and its pernicious background agents — solved the problem. This years-old “Chrome Is Bad” saga came to mind when I wrote about Google’s Gemini Mac app’s background agents. It seems as though Google eventually fixed these Chrome bugs — or Apple changed something in a MacOS update that fixed the bugs for them — but I’ve never seen a full explanation of the problem and eventual solution. Does anyone know what happened here? The main point is it never should have happened in the first place. A third-party app should just be a third-party app — not add components to your system software just so it can update itself when it isn’t running. Background agents and extensions are sometimes necessary to the functionality of a product. Checking for software updates to a browser or AI chatbot, when those apps aren’t running, is not necessary. The golden rule applies: imagine if every app on your system installed its own background agent to check for software updates. Chrome is a popular browser on the Mac, but it’s just a web browser. Other web browsers do just fine checking for updates from the browser itself when it’s running. If the user is actually using an app regularly, it’ll get plenty of chances to check for updates when it’s running. If the user isn’t regularly using an app, why in the world should that seldom-used app have software running all the time in the background? This sort of chaos is why Apple keeps iOS locked down. There are no third-party login items on iOS that run in the background — let alone ones with no option to disable. No third-party app can do anything that causes the iOS window manager to consume 80 percent of the CPU while ostensibly idle. There are obviously trade-offs here. I rely on a Mac for my workstation because the Mac gives me the power to potentially shoot myself in the foot. But iOS is an order of magnitude more popular than MacOS because you cannot shoot yourself in the foot with it, even though that means you can’t use it do things that would require that power.  ★