10 interesting stories served every morning and every evening.

Im going back to writing code by hand

blog.k10s.dev

09 May, 2026

This dev-log is get­ting a lot of at­ten­tion on HN (scary!): HN Thread.

To those who are com­ing here from HN: This started as an in­ves­ti­ga­tion or rather a ques­tion: How far I can get with build­ing a piece of soft­ware by keep­ing my­self com­pletely out of the loop”. The tl;dr of this dev log is that I still need to be in the loop to make any­thing mean­ing­ful. Take aways:

like em-dash” is to ai writ­ing, god-object” is to ai cod­ing

vibe-cod­ing makes every­thing feel cheap and you may end up los­ing fo­cus and build­ing bloat

let a hu­man (you) write the ar­chi­tec­ture and don’t just keep ask­ing it for fea­tures

And some AGENTS.md/CLAUDE.md di­rec­tives that I felt help me stay out of the loop a lit­tle more

Humans in­ter­ven­tion is still needed as of 10/05/2026. You can to­tally go back now! [3]

I

Here is k10s: https://​github.com/​shvb­sle/​k10s/​tree/​archive/​go-v0.4.0

234 com­mits. ~30 week­ends. Built en­tirely on vibe-coded ses­sions with Claude, when­ever my to­kens lasted long enough to ship some­thing.

I’m archiv­ing my TUI tool and rewrit­ing it from scratch.

k10s started as a GPU-aware Kubernetes dash­board (and my first foray into build­ing some­thing se­ri­ous with AI). Think k9s but built for the peo­ple run­ning NVIDIA clus­ters, peo­ple who ac­tu­ally care about GPU uti­liza­tion, DCGM met­rics, and which nodes are sit­ting idle burn­ing $32/hr. I built it in Go with Bubble Tea [1] and it worked.

For a while… :(

I learned over these 7 months is worth more than the 1690 lines of model.go I’m throw­ing away. And I think any­one do­ing se­ri­ous vibe-cod­ing can ben­e­fit from this, be­cause this part does­n’t sur­face much (I feel it gets buried un­der the demo reels and the ve­loc­ity wins).

tl;dr: AI writes fea­tures, not ar­chi­tec­ture. The longer you let it drive with­out con­straints, the worse the wreck­age gets. The ve­loc­ity makes you think you’re win­ning right up un­til the mo­ment every­thing col­lapses si­mul­ta­ne­ously.

II

vibe cod­ing high

I started k10s in late September 2025. The first few weeks were magic. I’d prompt Claude with add a pods view with live up­dates” and boom, it worked. Resource list views, name­space fil­ter­ing, log stream­ing, de­scribe pan­els, key­board nav­i­ga­tion. Each fea­ture landed clean be­cause the pro­ject was small enough that the AI could hold the whole thing in con­text.

The ba­sic k9s clone took maybe 3 week­ends. Resource views for pods, nodes, de­ploy­ments, ser­vices. A com­mand palette. Watch-based live up­dates. Vim key­bind­ings. All work­ing, all vibe-coded in sin­gle ses­sions. I was build­ing at maybe 10x my nor­mal speed and it felt in­cred­i­ble.

Then I wanted the main sell­ing point.

The whole rea­son k10s ex­ists is the GPU fleet view. A ded­i­cated screen that shows you every node’s GPU al­lo­ca­tion, uti­liza­tion from DCGM, tem­per­a­ture, power draw, mem­ory. Not buried in kubectl de­scribe node out­put, but right there in a pur­pose-built table with color-coded sta­tus. Idle nodes in yel­low. Busy in green. Saturated in red.

And Claude one-shot it. I prompted for the fleet view, it gen­er­ated the FleetView struct, the tab fil­ter­ing (GPU/CPU/All), the cus­tom ren­der­ing with al­lo­ca­tion bars. It looked beau­ti­ful. I was rid­ing the high.

Then I typed :rs pods to switch back to the pods view.

Nothing ren­dered. The table was empty. Live up­dates had stopped. I switched to nodes, it showed stale data from the fleet view’s fil­ter. I went back to fleet, the tab counts were wrong.

The god ob­ject had con­sumed it­self.

This is the ti­tle of the blog post. This is where I in­ter­vened for the first time. For 7 months I’d been prompt­ing and ship­ping with­out ever sit­ting down and ac­tu­ally read­ing the code Claude wrote. I’d look at the diff, ver­ify it com­piled, test the happy path, move on. But now some­thing was fun­da­men­tally bro­ken and I could­n’t just prompt my way out of it.

So I sat down and read model.go. All 1690 lines. I was hor­ri­fied.

Here’s what it looked like. One struct to rule them all:

type Model struct { // 3rd party UI com­po­nents table table.Model pag­i­na­tor pag­i­na­tor.Model com­mand­In­put tex­tin­put.Model help help.Model

// clus­ter info and state k8sClient *k8s.Client cur­rent­GVR schema.GroupVer­sion­Re­source re­source­Watcher watch.In­ter­face re­sources []k8s.OrderedResourceFields listOp­tions metav1.ListOp­tions clus­ter­Info *k8s.ClusterInfo log­Lines []k8s.LogLine de­scribeCon­tent string cur­rent­Name­space string nav­i­ga­tion­His­tory *NavigationHistory logView *LogViewState de­scribeView *DescribeViewState view­Mode ViewMode viewWidth int viewHeight int err er­ror plug­in­Reg­istry *plugins.Registry help­Modal *HelpModal de­scribeView­port *DescribeViewport logView­port *LogViewport logStream­Can­cel func() log­Li­nesChan <-chan k8s.Log­Line hor­i­zon­talOff­set int mouse *MouseHandler fleetView *FleetView cre­ation­Times []time.Time all­Re­sources []k8s.OrderedResourceFields // fleet’s un­fil­tered set all­Cre­ation­Times []time.Time // fleet’s time­stamps ra­wOb­jects []unstructured.Unstructured ageColumnIn­dex int // … }

UI wid­gets. K8s client. Per-view state for logs, de­scribe, fleet. Navigation his­tory. Caching. Mouse han­dling. All in one struct. And the Update() method was a 500-line func­tion dis­patch­ing on msg.(type) with 110 switch/​case branches.

This is the mo­ment I stopped vibe-cod­ing and started think­ing.

III

five tenets from the wreck­age

Here’s what I ex­tracted from 7 months of watch­ing AI gen­er­ate a code­base that slowly ate it­self. Each of these is some­thing I did wrong, why it hap­pens with AI-assisted cod­ing, and what you should ac­tu­ally put in your CLAUDE.md or agents.md to pre­vent it.

Tenet 1: AI builds fea­tures, not ar­chi­tec­ture.

Every time I prompted Claude for a fea­ture, it de­liv­ered. Perfectly. The fleet view worked on the first try. Log stream­ing worked. Mouse sup­port worked. The prob­lem is that each fea­ture was im­ple­mented in the con­text of make this work right now” with­out any aware­ness of the 49 other fea­tures shar­ing the same state.

Here’s what the re­sources­Load­edMsg han­dler looks like. This is the code that runs every time you switch views:

case re­sources­Load­edMsg: m.log­Lines = nil // Clear log lines when load­ing re­sources m.hor­i­zon­talOff­set = 0 // Reset hor­i­zon­tal scroll on re­source change

if m.cur­rent­GVR != msg.gvr && m.re­source­Watcher != nil { m.re­source­Watcher.Stop() m.re­source­Watcher = nil } m.cur­rent­GVR = msg.gvr m.cur­rent­Name­space = msg.name­space m.listOp­tions = msg.listOp­tions m.ra­wOb­jects = msg.ra­wOb­jects

// For nodes: store the full un­fil­tered set, clas­sify, then fil­ter if msg.gvr.Re­source == k8s.Re­sourceNodes && m.fleetView != nil { m.all­Re­sources = msg.re­sources m.all­Cre­ation­Times = msg.cre­ation­Times if len(msg.ra­wOb­jects) > 0 { m.fleetView.Clas­si­fyAnd­Count(m.ra­wOb­jectP­trs()) } m.ap­plyFleet­Fil­ter() } else { m.re­sources = msg.re­sources m.cre­ation­Times = msg.cre­ation­Times m.all­Re­sources = nil m.all­Cre­ation­Times = nil }

See the if msg.gvr.Re­source == k8s.Re­sourceNodes && m.fleetView != nil con­di­tional? That’s the fleet view be­ing spe­cial-cased in­side the generic re­source load­ing path. Every new view that needed cus­tom be­hav­ior got an­other branch here. And every branch needed to man­u­ally clear the right com­bi­na­tion of fields or the pre­vi­ous view’s data would bleed through.

How many = nil cleanup lines ex­ist in this file? I counted:

m.log­Lines = nil // Clear log lines when load­ing re­sources m.all­Re­sources = nil // Clear fleet data when not on nodes m.re­sources = nil // Clear re­sources when load­ing logs m.re­sources = nil // Clear re­sources when load­ing de­scribe view m.log­Lines = nil // Clear log lines when load­ing de­scribe view m.re­sources = nil // Clear re­sources when load­ing yaml view m.log­Lines = nil // Clear log lines when load­ing yaml view m.log­Lines = nil // … two more in other han­dlers m.log­Lines = nil

Nine man­ual nil as­sign­ments scat­tered across a 1690-line file. Miss one and you get ghost data from the pre­vi­ous view. This is what hap­pens when there’s no view iso­la­tion. AI can’t see this pat­tern de­cay­ing over time be­cause each prompt only touches one code path.

What to do in­stead: Write the ar­chi­tec­ture your­self be­fore any code. Not a vague de­sign doc. A con­crete set of in­ter­faces, mes­sage types, and own­er­ship rules. Then put those rules in your CLAUDE.md so the AI sees them on every prompt:

# Architecture Invariants (CLAUDE.md)

- Each view im­ple­ments the View trait. Views do NOT ac­cess other views’ state. - All async data ar­rives via AppMsg vari­ants. No di­rect field mu­ta­tion from back­ground tasks. - Adding a new view MUST NOT re­quire mod­i­fy­ing ex­ist­ing views. - The App struct is a thin router. It owns nav­i­ga­tion and mes­sage dis­patch. Nothing else.

The AI will fol­low these if you write them down. It just won’t in­vent them for you.

Tenet 2: The god ob­ject is the de­fault AI ar­ti­fact.

AI grav­i­tates to­ward sin­gle-struct-holds-every­thing be­cause it sat­is­fies the im­me­di­ate prompt with min­i­mal cer­e­mony. But it gets worse. Because there’s no view iso­la­tion, key han­dling be­comes a night­mare. Here’s the ac­tual key dis­patch for the s key:

case m.con­fig.Key­Bind.For(con­fig.Ac­tion­Tog­gleAu­to­Scroll, key): if m.cur­rent­GVR.Re­source == k8s.Re­sourceL­ogs { m.logView.Au­to­scroll = !m.logView.Autoscroll if m.logView.Au­to­scroll { m.table.Go­to­Bot­tom() } re­turn m, nil } // Shell exec for pods and con­tain­ers views if m.cur­rent­GVR.Re­source == k8s.Re­sour­ce­Pods { // … 20 lines to look up se­lected pod, get name, name­space … re­turn m, m.com­mand­With­Pre­flights( m.ex­ecIn­to­Pod(se­lect­ed­Name, se­lect­ed­Name­space), m.re­quire­Con­nec­tion, ) } if m.cur­rent­GVR.Re­source == k8s.Re­source­Con­tain­ers { // … con­tainer exec logic … re­turn m, m.com­mand­With­Pre­flights(m.ex­ecIn­to­Con­tainer(), m.re­quire­Con­nec­tion) } re­turn m, nil

One key­bind­ing. Three com­pletely dif­fer­ent be­hav­iors de­pend­ing on which view you’re in. The s key means autoscroll” in logs, shell” in pods, and shell into con­tainer” in con­tain­ers. This is all in one flat switch be­cause there are no per-view key maps. The AI gen­er­ated this be­cause I said add shell sup­port for pods” and it found the near­est key han­dler and jammed it in.

And look at how Enter works. This is the drill-down han­dler:

case m.con­fig.Key­Bind.For(con­fig.Ac­tion­Sub­mit, key): // Special han­dling for con­texts view if m.cur­rent­GVR.Re­source == contexts” { // … 12 lines … re­turn m, m.ex­e­cu­teC­tx­Com­mand([]string{con­textName}) } // Special han­dling for name­spaces view if m.cur­rent­GVR.Re­source == namespaces” { // … 12 lines … re­turn m, m.ex­e­cuteN­sCom­mand([]string{name­space­Name}) } if m.cur­rent­GVR.Re­source == k8s.Re­sourceL­ogs { re­turn m, nil } // … 25 more lines of generic drill-down …

Every view is a con­di­tional in a flat dis­patch. There are 20+ oc­cur­rences of m.cur­rent­GVR.Re­source == used as a type dis­crim­i­na­tor in this sin­gle file. Not types. String com­par­isons. Every new view means touch­ing every han­dler.

What to do in­stead: Put this in your CLAUDE.md:

# State Ownership Rules

- NEVER add fields to the App/Model struct for view-spe­cific state. - Each view is a sep­a­rate struct im­ple­ment­ing the View trait/​in­ter­face. - Each view de­clares its own key bind­ings. The app dis­patches keys to the ac­tive view. - If you need to add a key­bind­ing, add it to the rel­e­vant view’s keymap, not a global one. - Adding a view means adding a file. If your change re­quires mod­i­fy­ing ex­ist­ing views, stop and ask.

The AI will al­ways take the short­est path (“add an­other if-branch”). Your job is to make the short­est path also the cor­rect path by putting guardrails in the file it reads on every in­vo­ca­tion.

Tenet 3: Velocity il­lu­sion widens your scope.

This one’s psy­cho­log­i­cal, not tech­ni­cal, and I think it’s the most dan­ger­ous.

When I started k10s, I wanted a GPU-focused tool. For peo­ple run­ning train­ing clus­ters. A niche au­di­ence that I’m part of. But vibe-cod­ing made every­thing feel cheap. Oh I can add pods view in one ses­sion? Let me add de­ploy­ments too. And ser­vices. And a full com­mand palette. And mouse sup­port. And con­texts. And name­spaces.”

Suddenly I was build­ing k9s. A gen­eral-pur­pose Kubernetes TUI. For every­one. Because the AI made it feel like each fea­ture was free.

It was­n’t free. Each fea­ture was an­other branch in the god ob­ject. Here’s the key­bind­ing struct:

type keyMap struct { Up, Down, Left, Right key.Bind­ing GotoTop, GotoBottom key.Bind­ing AllNS, DefaultNS key.Bind­ing Enter, Back key.Bind­ing Command, Quit key.Bind­ing Fullscreen key.Bind­ing // log view Autoscroll key.Bind­ing // log view (also shell in pods!) ToggleTime key.Bind­ing // log view WrapText key.Bind­ing // log + de­scribe view CopyLogs key.Bind­ing // log view ToggleLineNums key.Bind­ing // de­scribe view Describe key.Bind­ing // re­source views YamlView key.Bind­ing // re­source views Edit key.Bind­ing // re­source views Shell key.Bind­ing // pods (CONFLICTS with Autoscroll!) FilterLogs key.Bind­ing // log view FleetTabNext key.Bind­ing // fleet view only FleetTabPrev key.Bind­ing // fleet view only }

One flat keymap for all views. Comments in parens show which view each bind­ing ap­plies to. Autoscroll and Shell are both s. This works” be­cause the dis­patch checks m.cur­rent­GVR.Re­source be­fore act­ing. But it means you can’t rea­son about key­bind­ings lo­cally. You have to trace through the en­tire 500-line Update func­tion to know what a key does.

The com­plex­ity was ac­cu­mu­lat­ing in­vis­i­bly while the ve­loc­ity met­ric said you’re ship­ping!”

What to do in­stead: Write a vi­sion doc that ex­plic­itly says who you’re NOT build­ing for, and put the scope bound­ary in your CLAUDE.md:

# Scope (do NOT ex­pand be­yond this)

k10s is for GPU clus­ter op­er­a­tors. Not all Kubernetes users. Supported views: fleet, node-de­tail, gpu-de­tail, work­load. That’s it. Do NOT add generic re­source views (pods, de­ploy­ments, ser­vices). Do NOT add fea­tures that du­pli­cate k9s func­tion­al­ity. If a fea­ture re­quest does­n’t serve some­one run­ning GPU train­ing jobs, re­ject it.

Vibe-coding makes you feel like you have in­fi­nite im­ple­men­ta­tion bud­get. You don’t. You have in­fi­nite LINE bud­get (the AI will gen­er­ate as much code as you want). But you have the same fi­nite com­plex­ity bud­get as al­ways. The ar­chi­tec­ture can only sup­port so many fea­tures be­fore it buck­les, re­gard­less of how fast you wrote them. The CLAUDE.md scope sec­tion is you say­ing no in ad­vance, be­fore the ve­loc­ity high con­vinces you to say yes.

Tenet 4: Positional data is a time bomb.

Every re­source in k10s was fetched from the Kubernetes API and im­me­di­ately flat­tened:

type OrderedResourceFields []string

Column iden­tity was purely po­si­tional. Here’s the sort func­tion for the fleet view. Look at the in­dex ac­cess:

func sort­Fil­tere­dResources(rows []k8s.OrderedResourceFields, times []time.Time, tab FleetTab) { sort.SliceS­table(in­dices, func(a, b int) bool { ra := rows[in­dices[a]] rb := rows[in­dices[b]]

switch tab { case FleetTabGPU: // Sort by Alloc col­umn (index 3) as­cend­ing al­locA, al­locB := ”, ” if len(ra) > 3 { al­locA = ra[3] } if len(rb) > 3 { al­locB = rb[3] } re­turn al­locA < al­locB

case FleetTabCPU: // Sort by Name col­umn (index 0) as­cend­ing nameA, nameB := ”, ” if len(ra) > 0 { nameA = ra[0] } if len(rb) > 0 { nameB = rb[0] } re­turn nameA < nameB

case FleetTabAll: // GPU nodes first, then CPU nodes. // Within GPU: sort by Alloc (index 3). // Within CPU: sort by Name (index 0). com­puteA, com­puteB := ”, ” if len(ra) > 2 { com­puteA = ra[2] } if len(rb) > 2 { com­puteB = rb[2] } aIs­GPU := strings.HasPre­fix(com­puteA, gpu”) bIs­GPU := strings.HasPre­fix(com­puteB, gpu”) // … } }) }

ra[3] is Alloc. ra[2] is Compute. ra[0] is Name. These are magic num­bers. The only thing con­nect­ing in­dex 3 to Alloc” is a com­ment and the col­umn or­der de­fined in re­source.views.json:

{ nodes”: { fields”: [ { name”: Name”, weight”: 0.28 }, { name”: Instance”, weight”: 0.15 }, { name”: Compute”, weight”: 0.12 }, { name”: Alloc”, weight”: 0.12 }, … ] } }

Add a col­umn be­tween Instance and Compute? Every sort, every con­di­tional ren­der, every place that says ra[2] or ra[3] is now silently wrong. The com­piler can’t help you be­cause it’s all []string. And the JSON con­fig can’t ex­press sort be­hav­ior, con­di­tional ren­der­ing, or cus­tom drill tar­gets, so those live in Go code that hard­codes the po­si­tional as­sump­tions from the JSON.

AI gen­er­ates this pat­tern be­cause it’s the short­est path from fetch data” to render table.” A []string sat­is­fies any table wid­get im­me­di­ately. Typed structs re­quire more cer­e­mony up­front. So the AI picks the fast path, and six months later you’re de­bug­ging why sort puts Name” val­ues in the Alloc” col­umn.

What to do in­stead: Put this di­rec­tive in your CLAUDE.md:

# Data Representation

- NEVER flat­ten struc­tured data into []string, Vec<String>, or po­si­tional ar­rays. - All data flows as typed structs (FleetNode, PodInfo, etc.) un­til the ren­der() call. - Column iden­tity comes from struct field names, not ar­ray in­dices. - Sort func­tions op­er­ate on typed fields, never on po­si­tional ac­cess like row[3]. - The ONLY place strings are cre­ated for dis­play is in­side ren­der()/​view() func­tions.

Then your typed struct makes im­pos­si­ble states im­pos­si­ble [2]:

struct FleetNode { name: String, in­stance_­type: String, com­pute_­class: ComputeClass, al­loc: GpuAlloc, }

You can’t sort by the wrong col­umn when columns are named fields. You can’t ac­ci­den­tally com­pare Alloc strings as names. The com­piler en­forces this for you. AI will al­ways pick Vec<String> be­cause it sat­is­fies the prompt faster. Your CLAUDE.md makes the typed path the path of least re­sis­tance.

Tenet 5: AI does­n’t own state tran­si­tions.

The Bubble Tea ar­chi­tec­ture has a beau­ti­ful idea: Update() is the only place state mu­tates, dri­ven by mes­sages. But k10s vi­o­lated this. The up­dateTableMsg han­dler spawned a clo­sure that mu­tated Model fields from in­side a gor­ou­tine:

case up­dateTableMsg: re­turn m, func() tea.Msg { // block on some­one send­ing the up­date mes­sage. <-m.updateTableChan // Preserve cur­sor po­si­tion across col­umn/​row up­dates so that // back­ground re­freshes don’t re­set the user’s se­lec­tion. saved­Cur­sor := max(m.table.Cur­sor(), 0) // run the nec­es­sary table view up­date calls. m.up­date­Columns(m.viewWidth) m.up­dateTable­Data() // Restore cur­sor, clamped to valid range. row­Count := len(m.table.Rows()) if row­Count > 0 { if saved­Cur­sor >= row­Count { saved­Cur­sor = row­Count - 1 } m.table.SetCur­sor(saved­Cur­sor) } re­turn up­dateTableMsg{} }

This re­turned func­tion (a tea.Cmd) is ex­e­cuted by Bubble Tea in a sep­a­rate gor­ou­tine. It calls m.up­date­Columns(m.viewWidth) and m.up­dateTable­Data() which read and write m.re­sources, m.table, m.viewWidth. Meanwhile, View() is called on the main gor­ou­tine read­ing the same fields. There’s no lock. No mu­tex. The chan­nel <-m.updateTableChan blocks the gor­ou­tine un­til some­one sends an up­date sig­nal, but noth­ing pre­vents View() from read­ing half-writ­ten state.

This is a text­book data race. It worked 99% of the time. Corrupted the dis­play 1% of the time in ways that made me think I was go­ing in­sane.

AI gen­er­ates this be­cause just mu­tate it in the clo­sure” is the short­est path to work­ing code. Proper mes­sage pass­ing (send a mes­sage back to Update(), let Update() ap­ply the mu­ta­tion atom­i­cally on the main loop) re­quires more types, more plumb­ing. The AI is op­ti­miz­ing for the prompt, not for cor­rect­ness un­der con­cur­rency.

What to do in­stead: All mu­ta­tions to ren­der-vis­i­ble state hap­pen on the main loop. Period. Background work­ers pro­duce data. They send it as a mes­sage. The main loop re­ceives the mes­sage and ap­plies it. This is the one rule you can­not break in con­cur­rent UI code.

// Background task: tx.send(AppMsg::Fleet­Data(nodes)).await;

// Main loop: match msg { AppMsg::FleetData(nodes) => { self.fleet_view.up­date_n­odes(nodes); } }

Mythos finds a curl vulnerability

daniel.haxx.se

yes, as in sin­gu­lar one.

Back in April 2026 Anthropic caused a lot of me­dia noise when they con­cluded that their new AI model Mythos is dan­ger­ously good at find­ing se­cu­rity flaws in source code. Apparently Mythos was so good at this that Anthropic would not re­lease this model to the pub­lic yet but in­stead trickle it out to a se­lected few com­pa­nies for a while to al­low a few good ones(?) to get a head start and fix the most press­ing prob­lems first, be­fore the gen­eral pop­u­lace would get their hands on it.

The whole world seemed to lose its mar­bles. Is this the end of the world as we know it? An amaz­ingly suc­cess­ful mar­ket­ing stunt for sure.

My (non-) ac­cess

Part of the deal with pro­ject Glasswing was that Anthropic also of­fered ac­cess to their lat­est AI model to Open Source pro­jects” via Linux Foundation. Linux Foundation let their pro­ject Alpha Omega han­dle this part, and I was con­tacted by their rep­re­sen­ta­tives. As lead de­vel­oper of curl I was of­fered ac­cess to the magic model and I gra­ciously ac­cepted the of­fer. Sure, I’d like to see what it can find in curl.

I signed the con­tract for get­ting ac­cess, but then noth­ing hap­pened. Weeks went past and I was told there was a hic­cup some­where and ac­cess was de­layed.

Eventually, I was in­stead of­fered that some­one else, who has ac­cess to the model, could run a scan and analy­sis on curl for me us­ing Mythos and send me a re­port. To me, the dis­tinc­tion is­n’t that im­por­tant. It’s not that I would have a lot of time to ex­plore lots of dif­fer­ent prompts and do­ing deep dive ad­ven­tures any­way. Getting the tool to gen­er­ate a first proper scan and analy­sis would be great, who­ever did it. I hap­pily ac­cepted this of­fer.

(I am pur­posely leav­ing out the iden­tity of the in­di­vid­ual(s) in­volved in get­ting the curl analy­sis done as it is not the point of this blog post.)

AI scans of curl

Before this first Mythos re­port, we had al­ready scanned curl with sev­eral dif­fer­ent very ca­pa­ble AI pow­ered tools (I mean in ad­di­tion to run­ning a num­ber of normal” sta­tic code an­a­lyz­ers all the time, us­ing the pick­i­est com­piler op­tions and do­ing fuzzing on it for years etc). Primarily AISLE, Zeropath and OpenAI’s Codex Security have been used to scru­ti­nize the code with AI. These tools and the analy­ses they have done have trig­gered some­where be­tween two and three hun­dred bug­fixes merged in curl through-out the re­cent 8 – 10 months or so. A bunch of the find­ings these AI tools re­ported were con­firmed vul­ner­a­bil­i­ties and have been pub­lished as CVEs. Probably a dozen or more.

Nowadays we also use tools like GitHub’s Copilot and Augment code to re­view pull re­quests, and their re­marks and com­plaints help us to land bet­ter code and avoid merg­ing new bugs. I mean, we still merge bugs of course but the PR re­view bots reg­u­larly high­light is­sues that we fix: our merges would be worse with­out them. The AI re­views are used in ad­di­tion to the hu­man re­views. They help us, they don’t re­place us.

We also see a high vol­ume of high qual­ity se­cu­rity re­ports flood­ing in: se­cu­rity re­searchers now use AI ex­ten­sively and ef­fec­tively.

Security is a top pri­or­ity for us in the curl pro­ject. We fol­low every guide­line and we do soft­ware en­gi­neer­ing prop­erly, to re­duce the num­ber of flaws in code. Scanning for flaws is just one of many steps to keep this ship safe. You need to search long and hard to find an­other soft­ware pro­ject that makes as much or goes fur­ther than curl, for soft­ware se­cu­rity.

May 6, 2026

It was with great an­tic­i­pa­tion we re­ceived the first source code analy­sis re­port gen­er­ated with Mythos. Another chance for us to find ar­eas to im­prove and bugs to fix. To make an even bet­ter curl.

This ini­tial scan was made on curl’s git repos­i­tory and its mas­ter branch of a cer­tain re­cent com­mit. It counted 178K lines of code an­a­lyzed in the src/ and lib/ sub­di­rec­to­ries.

The analy­sis de­tails sev­eral dif­fer­ent ap­proaches and meth­ods it has per­formed the search, and how it has fo­cused on try­ing to find which flaws. A fun note in the top of the re­port says:

curl is one of the most fuzzed and au­dited C code­bases in ex­is­tence (OSS-Fuzz, Coverity, CodeQL, mul­ti­ple paid au­dits). Finding any­thing in the hot paths (HTTP/1, TLS, URL pars­ing core) is un­likely.

curl is one of the most fuzzed and au­dited C code­bases in ex­is­tence (OSS-Fuzz, Coverity, CodeQL, mul­ti­ple paid au­dits). Finding any­thing in the hot paths (HTTP/1, TLS, URL pars­ing core) is un­likely.

… and it cor­rectly found no prob­lems in those ar­eas.

The size of curl

curl is cur­rently 176,000 lines of C code when we ex­clude blank lines. The source code con­sists of 660,000 words, which is 12% more words than the en­tire English edi­tion of the novel War and Peace.

On av­er­age, every sin­gle pro­duc­tion source code line of curl has been writ­ten (and then rewrit­ten) 4.14 times. We have pol­ished on this.

Right now, the ex­ist­ing pro­duc­tion code in git mas­ter that still re­mains, has been au­thored by 573 sep­a­rate in­di­vid­u­als. Over time, a to­tal of 1,465 in­di­vid­u­als have so far had their pro­posed changes merged into curl’s git repos­i­tory.

We have pub­lished 188 CVEs for curl up un­til now.

curl is in­stalled in over twenty bil­lion in­stances. It runs on over 110 op­er­at­ing sys­tems and 28 CPU ar­chi­tec­tures. It runs in every smart phone, tablet, car, TV, game con­sole and server on earth.

Five find­ings be­came one

The re­port con­cluded it found five Confirmed se­cu­rity vul­ner­a­bil­i­ties”. I think us­ing the term con­firmed is a lit­tle amus­ing when the AI says it con­fi­dently by it­self. Yes, the AI thinks they are con­firmed, but the curl se­cu­rity team has a slightly dif­fer­ent take.

Five is­sues felt like noth­ing as we had ex­pected an ex­ten­sive list. Once my curl se­cu­rity team fel­lows and I had poked on the this short list for a num­ber of hours and dug into the de­tails, we had trimmed the list down and were left with one con­firmed vul­ner­a­bil­ity. The other four were three false pos­i­tives (they high­lighted short­com­ings that are doc­u­mented in API doc­u­men­ta­tion) and the fourth we deemed just a bug”.

The sin­gle con­firmed vul­ner­a­bil­ity is go­ing to end up a sever­ity low CVE planned to get pub­lished in sync with our pend­ing next curl re­lease 8.21.0 in late June. The flaw is not go­ing to make any­one grasp for breath. All de­tails of that vul­ner­a­bil­ity will of course not get pub­lic be­fore then, so you need to hold out for de­tails on that.

The Mythos re­port on curl also con­tained a num­ber of spot­ted bugs that it con­cluded were not vul­ner­a­bil­i­ties, much like any new code an­a­lyzer does when you run it on hun­dreds of thou­sands of lines of code. All the bugs in the re­port are be­ing in­ves­ti­gated and one by one we are fix­ing those that we agree with.

All in all about twenty bugs that are de­scribed and ex­plained very nicely. Barely any false pos­i­tives, so I pre­sume they have had a rather high thresh­old for cer­tainty.

curl is cer­tainly get­ting bet­ter thanks to this re­port, but counted by the vol­ume of is­sues found, all the pre­vi­ous AI tools we have used have re­sulted in larger bug­fix amounts. This is only nat­ural of course since the first tools we ran had many more and eas­ier bugs to find. As we have fixed is­sues along the way, find­ing new ones are slowly be­com­ing harder. Additionally, a bug can be small or big so it’s not al­ways fair to just com­pare num­bers

Not par­tic­u­larly dangerous”

My per­sonal con­clu­sion can how­ever not end up with any­thing else than that the big hype around this model so far was pri­mar­ily mar­ket­ing. I see no ev­i­dence that this setup finds is­sues to any par­tic­u­lar higher or more ad­vanced de­gree than the other tools have done be­fore Mythos. Maybe this model is a lit­tle bit bet­ter, but even if it is, it is not bet­ter to a de­gree that seems to make a sig­nif­i­cant dent in code an­a­lyz­ing.

This is just one source code repos­i­tory and maybe it is much bet­ter on other things. I can only tell and com­ment on what it found here.

Still very good

But al­low me to high­light and re­it­er­ate what I have said be­fore: AI pow­ered code an­a­lyz­ers are sig­nif­i­cantly bet­ter at find­ing se­cu­rity flaws and mis­takes in source code than any tra­di­tional code an­a­lyz­ers did in the past. All mod­ern AI mod­els are good at this now. Anyone with time and some ex­per­i­men­tal spir­its can find se­cu­rity prob­lems now. The high qual­ity chaos is real.

Any pro­ject that has not scanned their source code with AI pow­ered tool­ing will likely find huge num­ber of flaws, bugs and pos­si­ble vul­ner­a­bil­i­ties with this new gen­er­a­tion of tools. Mythos will, and so will many of the oth­ers.

Not us­ing AI code an­a­lyz­ers in your pro­ject means that you leave ad­ver­saries and at­tack­ers time and op­por­tu­nity to find and ex­ploit the flaws you don’t find.

How AI an­a­lyz­ers dif­fer

They can spot when the com­ment says some­thing about the code and then con­clude that the code does not work as the com­ment says.

It can check code for plat­forms and con­fig­u­ra­tions we oth­er­wise can­not run an­a­lyz­ers for

It knows” de­tails about 3rd party li­braries and their APIs so it can de­tect abuse or bad as­sump­tions.

It knows” de­tails about pro­to­cols curl im­ple­ments and can ques­tion de­tails in the code that seem to vi­o­late or con­tra­dict pro­to­col spec­i­fi­ca­tions

They are typ­i­cally good at sum­ma­riz­ing and ex­plain­ing the flaw, some­thing which can be rather te­dious and dif­fi­cult with old style an­a­lyz­ers.

They can of­ten gen­er­ate and of­fer a patch for its found is­sue (even if the patch usu­ally is not a 100% fix).

More de­tails from the re­port

Zero mem­ory-safety vul­ner­a­bil­i­ties found.

Methodology note: this re­view is hand-dri­ven analy­sis us­ing LLM sub­agents for par­al­lel file reads, with every can­di­date find­ing re-ver­i­fied by di­rect source in­spec­tion in the main ses­sion be­fore be­ing recorded. The CVE to vari­ant-hunt map­ping was built from curl’s own vuln.json. No au­to­mated SAST tool­ing was used.

This out­come is con­sis­tent with curl’s sta­tus as one of the most heav­ily fuzzed and au­dited C code­bases. The de­fen­sive in­fra­struc­ture (capped dyn­bufs every­where, curlx_str_num­ber with ex­plicit max on every nu­meric parse, curlx_memdup0 over­flow guard, CURL_PRINTF for­mat-string en­force­ment, per-pro­to­col re­sponse-size caps, ping­pong 64KB line cap) sys­tem­at­i­cally closes the bug classes that would nor­mally be pro­duc­tive in a code­base this size.

Coverage now in­cludes: all mi­nor pro­to­cols, all file parsers, all TLS back­ends’ ver­ify paths, http/​1/​2/​3, ftp full depth, mprintf, x509asn1, doh, all auth mech­a­nisms, con­tent en­cod­ing, con­nec­tion reuse, ses­sion cache, CLI tool, plat­form-spe­cific code, and CI/build sup­ply chain.

AI finds ex­ist­ing kinds of er­rors

It should be noted that the AI tools find the usual and es­tab­lished kind of er­rors we al­ready know about. It just finds new in­stances of them.

We have not seen any AI so far re­port a vul­ner­a­bil­ity that would some­how be of a novel kind or some­thing to­tally new. They do not rein­vent the field in that way, but they do dig up more is­sues than any other tools did be­fore.

More to find

These were ab­solutely not the last bugs to find or re­port. Just while I was writ­ing the drafts for this blog post we have re­ceived more re­ports from se­cu­rity re­searchers about sus­pected prob­lems. The AI tools will im­prove fur­ther and the re­searchers can find new and dif­fer­ent ways to prompt the ex­ist­ing AIs to make them find more.

We have not reached the end of this yet.

I hope we can keep get­ting more curl scans done with Mythos and other AIs, over and over un­til they truly stop find­ing new prob­lems.

Credits

Thanks to Anthropic and Alpha Omega for pro­vid­ing the model, the tools and do­ing the scan for us. Thanks also to the in­di­vid­ual who did the scan for us. Much ap­pre­ci­ated!

Top im­age by Jin Kim from Pixabay

Thanks for fly­ing curl. It’s never dull.

Ratty — A GPU-rendered terminal emulator with inline 3D graphics 🐀🧀

ratty-term.org

Running local models on an M4 with 24GB memory

jola.dev

I’ve been ex­per­i­ment­ing with run­ning lo­cal mod­els on and off for a bit and I’ve fi­nally found a setup that seems to work rea­son­ably. It’s noth­ing like the out­put of a SOTA model, but the ex­cite­ment of be­ing able to have a lo­cal model do ba­sic tasks, re­search, and plan­ning, more than makes up for it! No in­ter­net con­nec­tion re­quired! Not to men­tion that it’s a way of re­duc­ing your de­pen­dence on big US tech, even if just a tiny bit.

I gotta say though, it’s not easy to get this stuff set up. First you have to choose how you’re run­ning the model: Ollama, llama.cpp or LM Studio. Each one comes with its own quirks and lim­i­ta­tions, and they don’t of­fer all the same mod­els. Then of course, you have to pick your model. You want the best model avail­able that fits in mem­ory and still gives you enough head­room to run your reg­u­lar as­sort­ment of Electron apps, not to men­tion some­thing where you can have at least a 64K con­text win­dow, but ide­ally 128K or more. Most re­cently I’ve tried Qwen 3.6 Q3, GPT-OSS 20B, Devstral Small 24B, which all tech­ni­cally fit in mem­ory but were in prac­tice un­us­able, and Gemma 4B that would run fine but re­ally strug­gle with tool use.

Then there’s a plethora of con­fig­u­ra­tion op­tions to tweak. From the more well-known, like tem­per­a­ture, to more es­o­teric op­tions like K Cache Quantization Type. Many of these tools come with a ba­sic rec­om­mended set of op­tions, but the ap­pro­pri­ate ones can de­pend on things like whether you’re en­abling think­ing or not!

Qwen 3.5 – 9B (4b quant)

qwen3.5 – 9b@q4_k_s (HuggingFace link) is the best model I’ve got­ten work­ing with a rea­son­able ~40 to­kens per sec­ond, think­ing en­abled, suc­cess­ful tool use, and a 128K con­text win­dow, run­ning on LM Studio. Compared to a SOTA model, it gets dis­tracted more eas­ily, some­times it gets stuck in loops, it’ll mis­in­ter­pret asks etc. But it’s sur­pris­ingly good for some­thing that can run on a 24GB Macbook Pro while leav­ing space for lots of other things run­ning too!

These are the rec­om­mended set­tings for think­ing mode and cod­ing work:

Thinking mode for pre­cise cod­ing tasks (e.g., WebDev):

tem­per­a­ture=0.6, top_p=0.95, top_k=20, min_p=0.0, pres­ence_penalty=0.0, rep­e­ti­tion_penalty=1.0

Thinking mode for pre­cise cod­ing tasks (e.g., WebDev):

tem­per­a­ture=0.6, top_p=0.95, top_k=20, min_p=0.0, pres­ence_penalty=0.0, rep­e­ti­tion_penalty=1.0

To en­able think­ing I also had to se­lect the model, go to con­fig­u­ra­tion, scroll to the bot­tom of the Inference tab, and add {%- set en­able_­think­ing = true %} to the Prompt Template.

I’ve been us­ing it through both pi and OpenCode. I still haven’t quite made my mind up on with one I pre­fer. Pi feels a bit snap­pier, but al­though I re­ally ap­pre­ci­ate the idea of the har­ness build­ing it­self and all that cus­tomiza­tion, I can’t help but wish it came with some sen­si­ble de­faults. I feel like you could eas­ily end up spend­ing more time tweak­ing your pi set up to be just right, than you do on your ac­tual pro­jects!

Pi setup

Here’s the ~/.pi/agent/models.json:

{ providers”: { lmstudio”: { baseUrl”: http://​lo­cal­host:1234/​v1, api”: openai-completions”, apiKey”: lm-studio”, models”: [ { id”: qwen3.5 – 9b@q4_k_s”, reasoning”: true, compat”: { thinkingFormat”: qwen-chat-template” } } ] } } }

and to hide the dis­tract­ing think­ing, add hideThinkingBlock”: true to your ~/.pi/agent/settings.json.

OpenCode setup

~/.config/opencode/opencode.json

{ $schema”: https://​open­code.ai/​con­fig.json, provider”: { lmstudio”: { npm”: @ai-sdk/openai-compatible”, name”: LM Studio (local)”, options”: { baseURL”: http://​127.0.0.1:1234/​v1 }, models”: { qwen3.5 – 9b@q4_k_s”: { name”: Qwen 3.5 9B Q4_K_S”, tools”: true, context_length”: 131072, max_tokens”: 32768 } } } }, model”: lmstudio/qwen3.5 – 9b@q4_k_s” }

Comparison with SOTA mod­els

A model like Qwen 3.5 9B (Q4) is nowhere near be­ing able to in­de­pen­dently solve com­plex prob­lems over longer pe­riod of time, like SOTA mod­els are. There’s no point in ask­ing it to build an en­tire app in one go, you’ll just burn your thighs with­out get­ting any­thing out of it.

What does work is a more in­ter­ac­tive work­flow where you’re clearly com­mu­ni­cat­ing with the model step by step, and giv­ing it a lot of guid­ance. I’m sure that sounds point­less to many of you, why use a model where you have to babysit it as it works, but I ac­tu­ally found that it en­cour­aged me to be more en­gaged. The down­side to work­ing with SOTA mod­els is that they make it too easy to of­fload all cog­ni­tive ef­fort, even where you’re try­ing to ac­tively pre­vent that from hap­pen­ing.

With the lo­cal modal I have to take on a lot more of the think­ing and plan­ning, I have to be a lot more spe­cific, but it will still act as a re­search as­sis­tant, a rub­ber duck, and a sa­vant with in­stant re­call of a lot of pro­gram­ming lan­guage de­tails and com­mand line evo­ca­tions. It’s not the 10x pro­duc­tiv­ity boost that the big AI com­pa­nies mar­ket, but it’s some­thing, and it’s in­ter­est­ing.

To give you an idea of some things that work and don’t, here are some very ba­sic ex­am­ples.

Example 1:

I wanted to bump the Elixir lin­ter credo to the lat­est ver­sion and I got warn­ings out of my code. As an ex­per­i­ment, I asked Qwen to take a look.

me: run mix credo –strict and sug­gest how to solve it, don’t edit

Qwen: Credo Warnings There are 4 warn­ings in your test files. The is­sue is us­ing length/​1 to check if lists are non-empty. Credo rec­om­mends com­par­ing against an empty list in­stead. Warnings: 1. test/​jo­la_de­v_web/​con­trollers/​blog_­con­troller_test.exs:11 - as­sert length(conn.as­signs.posts) > 0 2. test/​jo­la_de­v_web/​con­trollers/​blog_­con­troller_test.exs:22 - as­sert length(conn.as­signs.posts) > 0 3. test/​jo­la_dev/​blog_test.exs:10 - as­sert length(posts) > 0 4. test/​jo­la_dev/​blog_test.exs:23 - as­sert length(tags) > 0 How to Fix Replace each length(list) > 0 with list != []: blog_­con­troller_test.exs: # Line 11 as­sert conn.as­signs.posts != [] # Line 22 as­sert conn.as­signs.posts != [] blog_test.exs: # Line 10 as­sert posts != [] # Line 23 as­sert tags != [] This is more id­iomatic in Elixir and avoids the over­head of com­put­ing the list length.

I asked Qwen to make the ed­its and it did 4 par­al­lel ed­its, very clean. Overall this was a very sim­ple task that I could’ve done my­self by tab­bing back and forth be­tween the ter­mi­nal and my ed­i­tor to get the line num­bers to edit. Not a big dif­fer­ence in ef­fort, but nice and con­ve­nient.

Example 2:

After some de­pen­dency bumps I had a de­pend­abot PR with git con­flicts that de­pend­abot for some rea­son was re­fus­ing to re­base. I pulled it down, re­based, and asked Qwen to take a look. It was a very sim­ple con­flict to re­solve, just take the newer ver­sion of each, and the model rec­og­nized that.

I can see the con­flict. Here’s what’s hap­pen­ing: HEAD (your cur­rent branch): - sen­try: 13.0.1 - tail­wind: 0.3.1 Other side (commit be­ing re­based): - sen­try: 12.0.3 - tail­wind: 0.4.1 You have di­ver­gent de­pen­dency bumps. Here are your op­tions: Option 1: Take both up­dates (recommended) - Keep sen­try 13.0.1 from HEAD - Keep tail­wind 0.4.1 from the other side - This gives you the lat­est of both deps Option 2: Take only sen­try up­date - Keep sen­try 13.0.1 - Keep tail­wind 0.3.1 Option 3: Take only tail­wind up­date - Keep sen­try 12.0.3 - Keep tail­wind 0.4.1 Which ap­proach do you want to take?

However, when asked to make the change, it for­got to make the edit and in­stead just tried to add the changes and con­tinue the re­base, with the con­flict mark­ers still in place.

> Thinking: The user wants to take both up­dates - sen­try 13.0.1 and tail­wind 0.4.1. I need to re­solve the con­flict by keep­ing the HEAD ver­sion for sen­try and the other side ver­sion for tail­wind. I’ll use git add to stage the re­solved file. –– # Stage re­solved mix.lock and con­tinue re­base $ git add mix.lock && git re­base –continue Vim: Warning: Output is not to a ter­mi­nal Vim: Warning: Input is not from a ter­mi­nal ~/workspace/mixtli/.git/COMMIT_EDITMSG” 32L, 1047BBump tail­wind from 0.3.1 to 0.4.1 Bumps [tailwind](https://​github.com/​phoenixframe­work/​tail­wind) from 0.3.1 to 0.44.1. - [Changelog](https://​github.com/​phoenixframe­work/​tail­wind/​blob/​main/​CHANGELOG.mmd) - [Commits](https://​github.com/​phoenixframe­work/​tail­wind/​com­pare/​v0.3.1…v0.4.11)

Additionally it failed to rec­og­nize that git re­base –continue opens an ed­i­tor, and OpenCode then pro­ceeded to hang, al­though that might just have been a one-off.

Conclusion

Anyway, LLMs are in­cred­i­bly flex­i­ble and there’s a mil­lion things even a lo­cal model could do. Your imag­i­na­tion is the limit. Local mod­els have se­ri­ous trade­offs, but they come with some pretty at­trac­tive ben­e­fits:

No in­ter­net con­nec­tion re­quired, you can work on the plane!

The cost is lim­ited to the elec­tric­ity you’re us­ing, as­sum­ing you were gonna buy a com­puter any­way. No sub­scrip­tion re­quired.

There’s still go­ing to be a se­ri­ous en­vi­ron­men­tal cost of train­ing these mod­els, but the open model com­pa­nies are nowhere near the top of the list in en­vi­ron­men­tal im­pact, and us­ing your own hard­ware means less data cen­ters.

It’s fun to tin­ker.

LLMs have had a huge im­pact on our world, and much of it not great, but it’s ob­vi­ous that they’re here to stay. Experimenting with lo­cal mod­els feels like a more sus­tain­able and pos­i­tive way to in­ter­act with this tech­nol­ogy. And hon­estly, it’s a lot of fun, even when it does the wrong thing!

Google account registration now requires sending an SMS via phone instead of receiving an SMS

discuss.privacyguides.net

March 8, 2026, 2:20pm

1

I have tried it my­self, the reg­is­tra­tion is no longer pos­si­ble with the QR code. Supposedly, us­ing the QR code on the smart­phone trig­gers an SMS sent from your phone to Google in or­der to ver­ify your phone num­ber.

Supposedly, this is for se­cu­rity. A valid ar­gu­ment, since fin­ish is harder this way, al­though not im­pos­si­ble. However, this pro­hibits the use of ser­vices like SMSpool, too.

Does any­one have any ideas how to han­dle ac­count reg­is­tra­tion in the fu­ture?

*phishing

This only stops your av­er­age user. Google ac­counts are sold on a va­ri­ety of mar­ket­places and have been for a long time.

2 Likes

The av­er­age user is­n’t us­ing SMS ver­i­fi­ca­tion ser­vices to be­gin with. At best, that’s your av­er­age pri­vacy-fo­cused in­di­vid­ual. Now, how does the av­er­age pri­vacy-minded in­di­vid­ual best ap­proach cre­at­ing a new Google ac­count? Buying an ac­count second-hand” comes with its own risks, be­cause you never know who the ac­count was as­so­ci­ated with pre­vi­ously.

3 Likes

Scott

March 9, 2026, 9:36am

5

You just wait, some­one will come up with a ser­vice that sends a sms to google.

Damn it… Google keeps clos­ing more and more. Hope nerds find a work around soon.

I ad­mire your con­fi­dence and hope you are right.

I am cu­ri­ous, is QR code ver­i­fi­ca­tion cur­rently uni­ver­sal to all coun­tries?

Also, sup­pose I am on hol­i­day in Italy, which is one of the many coun­tries that re­quires ID reg­is­tra­tion to buy or use a SIM. I’m in Italy for only a week and buy a SIM there, which is tied to my ID.

While I’m there I use my Italian num­ber to cre­ate an anonymous” Google ac­count. Upon cre­at­ing my Google ac­count, I im­me­di­ately en­able 2FA via au­then­ti­ca­tion app and YubiKey, and save my re­cov­ery codes. I am able to log into my Google ac­count with­out SMS ver­i­fi­ca­tion.

I go back to my coun­try, and keep us­ing my Google ac­count with­out ever be­ing prompted to ver­ify my num­ber. Because I don’t live in Italy, my Italian num­ber quickly gets re­as­signed.

I keep us­ing my Google ac­counts for months and years, with­out every need­ing to ver­ify my num­ber.

Can Google trace the ac­count back to my real iden­tity from the Italian num­ber I used?

Do phone net­work com­pa­nies or gov­ern­ments keep a record of all the peo­ple who have owned the same num­ber?

This is some­thing worth in­ves­ti­gat­ing in the coun­try that you live in. I would like to be­lieve that if I owned a phone num­ber for just a cou­ple of months be­fore it was as­signed to some­one else, Google would not be able to iden­tify me.

I know for a fact that Google does keep a record of all the phone num­bers you have used with them. However, they will gen­er­ally not let you ver­ify your ac­count with a num­ber you don’t own any­more. I know lots of peo­ple who for­get to up­date their num­ber with Google when they change it.

ph00lt0

March 9, 2026, 1:27pm

8

Sending a SMS that is quite odd given phone spoof­ing op­tions. I hope they are not stu­pid enough to use that for MFA.

1 Like

Scott

March 9, 2026, 2:41pm

9

@james1992

Why are you al­ways so neg­a­tive? I put you on ig­nore a while ago so don’t waste time an­swer­ing. It’s more a ques­tion you should prob­a­bly ask your­self.

1 Like

According to this ar­ti­cle from February 2025, Google planned to use it for all SMS au­then­ti­ca­tion, not just reg­is­tra­tion.

Although it’s hard to tell how dif­fi­cult it is to spoof the num­ber/​text mes­sage. Google does­n’t give you a code to send man­u­ally.

I don’t like the idea of po­ten­tially re­veal­ing more de­tails about your de­vice and lo­ca­tion when you scan the QR code.

I also won­der what about peo­ple with dumb phones? Is it fair to ex­pect them to buy a smart­phone?

Just a cou­ple of years ago, I had a boss who I no­ticed had a dumb phone. He was rel­a­tively young, in his 40s, and de­lib­er­ately used a dumb phone. I never asked him why, but I don’t think it was be­cause he was­n’t smart enough to use smart­phone. If some peo­ple still use dumb phones it is un­fair to ex­pect them to switch.

In re­la­tion to this, I also ask my­self the fol­low­ing. Suppose you buy a French sim card in France, but then use that same SIM card in Japan. You use that SIM card to reg­is­ter a Google ac­count from Japan.

Will Google be able to de­tect you’re in Japan (assuming you’re us­ing a VPN) or will they still as­sume your lo­ca­tion is France?

kama (Kama)

May 11, 2026, 8:15pm

12

I think a se­cu­rity sys­tem is at work there, and based on a cer­tain set of met­rics, it de­ter­mines whether or not to send an SMS. Sometimes a QR code ap­pears for me, and some­times it does­n’t. Similarly, when a QR code does ap­pear and I scan it on my phone, some­times I have to send an SMS, and some­times I don’t. It all de­pends on the qual­ity of the proxy and other fac­tors.

The Top Cop: Driver accused of DUI tracks missing laptop to Illinois State trooper's house

abc7chicago.com

CHICAGO (WLS) — This is the sec­ond part to a two-part se­ries. To read part one, click here.

A restau­rant ex­ec­u­tive ar­rested by an Illinois State Police trooper on DUI charges told the ABC 7 I-Team when he dis­cov­ered his MacBook was miss­ing from his car, he tracked it to the house of the trooper who ar­rested him.

What fol­lowed was cap­tured in a 911 call record­ing, a cell phone video, and an in­ter­nal in­ves­ti­ga­tion by the Illinois State Police, all ob­tained by the I-Team.

For three years, ISP Trooper Kevin Bradley was named by a non­profit as the state’s Top Cop”: A moniker given to the mem­ber of law en­force­ment who has made the most DUI ar­rests statewide.

Over that time, hun­dreds of dri­vers were ar­rested by Bradley for DUI in Cook and DuPage Counties.

But as the I-Team pre­vi­ously re­ported, pub­lic de­fend­ers and civil rights at­tor­neys have ac­cused Bradley of fabricating ev­i­dence” and vi­o­lat­ing dri­vers’ civil rights, ar­gu­ing many of those crim­i­nal cases were later dis­missed prior to ad­ju­di­ca­tion, or they re­sulted in dri­vers re­ceiv­ing not guilty ver­dicts.

Local restau­rant ex­ec­u­tive Sherard Holland is one of those dri­vers.

It was just a reg­u­lar, nor­mal day,” Holland ex­plained. Doing a fa­vor for a friend of mine, trav­el­ing to pick them up and we were go­ing home when I un­for­tu­nately made con­tact with that trooper.”

As the sun rose in the early morn­ing hours of June 2, 2024, Holland says he was con­fused when he saw the po­lice lights in his rearview mir­ror.

The son of a Chicago po­lice of­fi­cer, Holland says he was the des­ig­nated dri­ver for a co-worker af­ter work­ing overnight when he was pulled over by Trooper Bradley.

The I-Team ob­tained a copy of the troop­er’s traf­fic stop re­port and dash­board cam­era footage from that morn­ing.

A dri­ver ac­cused of DUI tracked his miss­ing lap­top to Illinois State Police Trooper Kevin Bradley’s house. The ABC7 I-Team is in­ves­ti­gat­ing.

I pulled you over be­cause you swerved,” Bradley can be heard say­ing to Holland at his dri­ver’s side win­dow.

After speak­ing with Holland, Trooper Bradley wrote in his re­port he could smell the odor of an al­co­holic bev­er­age emit­ting from the ve­hi­cle.”

Bradley then asked Holland to relocate” by dri­ving down the road to a gas sta­tion in Worth Township, pass­ing through sev­eral in­ter­sec­tions and traf­fic lights.

At the gas sta­tion, Bradley ac­cused Holland of dri­ving un­der the in­flu­ence. When asked if he would sub­mit to field so­bri­ety tests, Holland calmly re­fused.

No, thank you,” Holland told Bradley in the footage.

Bradley took Holland into cus­tody for felony DUI and in the dash­board cam­era footage, while Holland was in the state troop­er’s ve­hi­cle, Bradley can be seen search­ing through Holland’s ve­hi­cle be­fore his car was towed.

Missing MacBook

Later that day, when Holland needed his MacBook, he said he no­ticed it was­n’t listed on his in­ven­tory slip, so he as­sumed it must be with his car at the tow yard.

I de­cided to ping my MacBook,” Holland told the I-Team, and it pinged to an ad­dress.”

Using Apple’s Find My” fea­ture, Holland says his MacBook was not ping­ing at the tow yard with his car, rather it was show­ing up at a Tinley Park home.

I was fear­ful of go­ing to re­trieve my item,” Holland ex­plained. And I just had to mo­ti­vate my­self and say, Hey, I’m go­ing to go get it.’”

Holland says he found his courage, and drove over to the ad­dress, where af­ter knock­ing on the front door, he was even­tu­ally met by Trooper Bradley.

He de­nied it and be­gan to ar­gue with me,” Holland said. And I de­cided to call the po­lice.”

After fil­ing a Freedom of Information Act re­quest with the Tinley Park Police Department, the I-Team ob­tained a record­ing of that 911 call.

In it, Holland can be heard speak­ing to a dis­patcher.

I have an iMac that was stolen last night,” Holland told the dis­patcher, re­fer­ring to his MacBook.

And what did they say when you con­fronted them then?” the dis­patcher asked Holland.

Holland told the I-Team while he was on the phone with the dis­patcher, Bradley told him to end the call. In the 911 record­ing, you can hear Holland say, How else would I have your ad­dress? OK, I’ll hang up. I’ll hang up,” and then the call ends.

Holland and his at­tor­ney pro­vided the I-Team a cell-phone video clip that picks up shortly af­ter that 911 call ended, recorded by Holland’s wife who was wait­ing in his car out­side of the Tinley Park home.

In the video, Trooper Bradley is seen walk­ing out and hand­ing Holland his MacBook. Bradley then opens his garage door to show Holland his State Police ve­hi­cle parked in­side, telling Holland the lap­top was ac­ci­den­tally left in his state ve­hi­cle.

It was a very trau­matic in­ter­ac­tion with him,” Holland told the I-Team.

The Tinley Park Police Department dis­patcher even­tu­ally called Holland back.

Is every­thing okay?” the dis­patcher can be heard ask­ing. You’re fine?”

Yeah, he’s a po­lice of­fi­cer and for some rea­son he took my MacBook home with him,” Holland replied.

Oh, gotcha,” the dis­patcher said. You’ll prob­a­bly want to speak to a su­per­vi­sor over there.”

That’s what Holland did: He filed a com­plaint with the Illinois State Police, and the I-Team ob­tained a copy of the state’s in­ter­nal in­ves­ti­ga­tion into the com­plaint.

According to the find­ings, in­ves­ti­ga­tors de­ter­mined Trooper Bradley never re­ported the in­ter­ac­tion with Holland over his MacBook to Bradley’s su­per­vi­sors, nor did he make note of it in his re­ports.

In a tran­script of an in­ter­view Bradley did with in­ter­nal in­ves­ti­ga­tors as part of the in­ves­ti­ga­tion, when Bradley was asked why he took the lap­top, he said he was do­ing Holland a favor.”

I kept it for his cour­tesy, like I said with his phone, key and wal­let,” Bradley told in­ves­ti­ga­tors. It’s my mis­take. I for­got to give him his stuff back and he tracked it.”

The re­port states in­ves­ti­ga­tors de­ter­mined Bradley had vi­o­lated State Police poli­cies, and he was sus­pended for one day.

When the I-Team shared this with Holland, he said, I feel dis­heart­ened by that. I feel let down by, again, peo­ple who should be en­trusted and should be held ac­count­able for their ac­tions.”

I’m out­raged,” said Brandon Brown, Holland’s at­tor­ney. Outraged as a fel­low Cook County res­i­dent to think that some­thing like that could hap­pen.”

What if he did­n’t call 911?” Brown asked, What if he did­n’t have the Find My iPhone ap­pli­ca­tion?”

After months of court hear­ings for the DUI charges, a bench trial found Holland not guilty.”

Holland is now su­ing the state and Trooper Bradley al­leg­ing his civil rights were vi­o­lated.

Bradley did not re­spond to the I-Team’s re­peated re­quests for com­ment. In court fil­ings, at­tor­neys rep­re­sent­ing the state and Bradley have ar­gued Holland’s law­suit should be dis­missed as the trooper has sovereign im­mu­nity” as a mem­ber of law en­force­ment, and that it was a lawful” traf­fic stop.

How many other peo­ple?’

An I-Team analy­sis of Cook County court records found out of 319 DUI pros­e­cu­tions stem­ming from ar­rests made by Trooper Bradley since 2023, 174 cases were dis­missed be­fore ad­ju­di­ca­tion, or the dri­vers were found not guilty, like in Holland’s case.

According to court records, 105 dri­vers were found guilty, with 96 of those dri­vers ac­cept­ing plea deals for lesser charges.

As of last month, 40 cases are still pend­ing.

Brown says there are crit­i­cal ques­tions that need to be an­swered about Bradley’s ar­rests.

How many other peo­ple like Sherard, who maybe could­n’t af­ford a lawyer… Maybe they pled guilty or maybe they were found guilty and per­haps their con­duct did­n’t ac­tu­ally match what was al­leged,” Brown said.

A spokesper­son for the Illinois State Police said, ISP has strong over­sight of all of­fi­cers and ad­dresses any dis­crep­an­cies or com­plaints when they are iden­ti­fied.”

It would be ir­re­spon­si­ble not to ar­rest and re­move a per­son off the roads who is sus­pected of im­paired dri­ving,” a spokesper­son for ISP told the I-Team. Securing con­vic­tions for DUIs in a court of law is a sep­a­rate process from the role troop­ers and other law en­force­ment of­fi­cers play.”

The ISP state­ment reads, A trooper makes an ar­rest when there is prob­a­ble cause… Ultimately, it is up to the pros­e­cu­tor to de­ter­mine whether they can meet the thresh­old of proof be­yond a rea­son­able doubt.”

For dri­vers like Holland, Brown says ar­rests for DUI are se­ri­ous and can have a last­ing im­pact.

It can have a life chang­ing ex­pe­ri­ence,” Brown said. It is dev­as­tat­ing. And if you’re in­no­cent, that’s some­thing that stays with you.”

Court over­time

For every DUI ar­rest made, state po­lice troop­ers must ap­pear in court, and in ev­i­dence mo­tions filed with the court, at­tor­neys have said this has led to a stag­ger­ing amount of over­time pay for Trooper Bradley.

State records show in 2024, Bradley nearly tripled his salary, earn­ing nearly $250,000 in one year.

That’s more than the salary of the Illinois State Police di­rec­tor.

A spokesper­son for ISP told the I-Team Bradley is cur­rently on med­ical leave af­ter suf­fer­ing in­juries from an ac­ci­dent while he was work­ing.

Copyright © 2026 WLS-TV. All Rights Reserved.

Obsidian Plugin Abused in Social Engineering Campaign to Deliver New PHANTOMPULSE RAT

cyber.netsecops.io

Executive Summary

Security re­searchers have iden­ti­fied a highly tar­geted so­cial en­gi­neer­ing cam­paign (REF6598) that weaponizes the Obsidian note-tak­ing ap­pli­ca­tion to de­liver a pre­vi­ously un­doc­u­mented Remote Access Trojan (RAT) named PHANTOMPULSE. The cam­paign tar­gets in­di­vid­u­als in the fi­nan­cial and cryp­tocur­rency sec­tors on both Windows and ma­cOS. Attackers use plat­forms like LinkedIn and Telegram to build trust be­fore lur­ing vic­tims into a ma­li­cious shared Obsidian vault. The at­tack chain re­lies on trick­ing the user into en­abling a com­mu­nity plu­gin, which then ex­e­cutes code to de­ploy the RAT. PHANTOMPULSE demon­strates ad­vanced ca­pa­bil­i­ties, in­clud­ing us­ing the Ethereum blockchain to dy­nam­i­cally re­solve its com­mand-and-con­trol (C2) server ad­dress, mak­ing it highly re­silient to take­downs.

Threat Overview

The at­tack, des­ig­nated REF6598, is a multi-stage so­cial en­gi­neer­ing ef­fort. Threat ac­tors pose as ven­ture cap­i­tal­ists and en­gage with tar­gets on pro­fes­sional net­work­ing sites be­fore mov­ing the con­ver­sa­tion to a pri­vate Telegram group. The pri­mary lure is an in­vi­ta­tion to col­lab­o­rate via a shared, cloud-hosted Obsidian vault.

Once the vic­tim opens the shared vault, the in­fec­tion is trig­gered by so­cial en­gi­neer­ing. The vic­tim is prompted to en­able the Installed com­mu­nity plu­g­ins” syn­chro­niza­tion fea­ture. This seem­ingly in­nocu­ous ac­tion, which re­quires man­ual user ap­proval, is the key to the com­pro­mise. It en­ables ma­li­cious ver­sions of le­git­i­mate Obsidian plu­g­ins (‘Shell Commands’ and Hider’) that are pre­sent in the shared vault.

Technical Analysis

The at­tack chain dif­fers slightly be­tween Windows and ma­cOS but fol­lows the same gen­eral prin­ci­ple:

Initial Access (T1566.002): The at­tacker uses so­cial en­gi­neer­ing on LinkedIn/Telegram to con­vince the tar­get to open a ma­li­cious shared Obsidian vault.

Execution (T1204.002): The user is ma­nip­u­lated into en­abling com­mu­nity plu­g­ins within Obsidian. This ac­tion ex­e­cutes a ma­li­cious script via the com­pro­mised Shell Commands’ plu­gin.

Staging: On Windows, a PowerShell script is ex­e­cuted. This script drops a loader known as PHANTOMPULL. On ma­cOS, a sim­i­lar process oc­curs us­ing AppleScript.

Payload Delivery: The PHANTOMPULL loader de­crypts and launches the fi­nal pay­load, the PHANTOMPULSE RAT, di­rectly into mem­ory to evade file-based de­tec­tion (T1055).

Command and Control (T1102.002): PHANTOMPULSE uses a novel C2 mech­a­nism. It queries the Ethereum blockchain for the lat­est trans­ac­tion from a hard-coded wal­let ad­dress. The C2 server’s IP ad­dress is em­bed­ded within this trans­ac­tion data, pro­vid­ing a de­cen­tral­ized and cen­sor­ship-re­sis­tant way for the mal­ware to re­ceive in­struc­tions.

Once ac­tive, PHANTOMPULSE can cap­ture key­strokes, take screen­shots, ex­fil­trate files, and ex­e­cute ar­bi­trary com­mands.

Impact Assessment

A suc­cess­ful com­pro­mise gives the at­tacker full ac­cess to the vic­tim’s ma­chine. For pro­fes­sion­als in fi­nance and crypto, this could lead to the theft of sen­si­tive cor­po­rate data, in­tel­lec­tual prop­erty, trad­ing strate­gies, and, most crit­i­cally, cryp­tocur­rency wal­let keys and ex­change cre­den­tials. The cross-plat­form na­ture of the at­tack broad­ens its po­ten­tial vic­tim pool. The use of a blockchain-based C2 demon­strates a high level of so­phis­ti­ca­tion, mak­ing the threat in­fra­struc­ture dif­fi­cult to dis­rupt.

Cyber Observables for Detection

Type

process_­name

Value

Obsidian.exe

Description

Monitor for Obsidian spawn­ing child processes like pow­er­shell.exe, cmd.exe, or os­ascript.

Type

com­mand_­line_­pat­tern

Value

pow­er­shell -ExecutionPolicy Bypass

Description

Suspicious PowerShell ex­e­cu­tion, es­pe­cially when ini­ti­ated by a non-stan­dard ap­pli­ca­tion like Obsidian.

Type

net­work_­traf­fic_­pat­tern

Value

Outbound con­nec­tions to Ethereum blockchain nodes or gate­ways from un­ex­pected processes.

Description

Could in­di­cate PHANTOMPULSE at­tempt­ing to re­solve its C2 ad­dress.

Type

file_­path

Value

[Vault]/.obsidian/plugins/

Description

Monitor for the cre­ation or mod­i­fi­ca­tion of files within the Obsidian plu­g­ins di­rec­tory, es­pe­cially out­side of the of­fi­cial plu­gin mar­ket­place.

Detection & Response

Process Monitoring (D3-PA: Process Analysis): Implement EDR rules to de­tect and alert when the Obsidian process spawns com­mand-line in­ter­preters (powershell.exe, cmd.exe, bash, os­ascript). This is highly anom­alous be­hav­ior.

User Training: Educate users, es­pe­cially those in high-risk in­dus­tries, about the dan­gers of so­cial en­gi­neer­ing and the spe­cific tac­tic of abus­ing col­lab­o­ra­tion tool fea­tures like shared vaults and plu­g­ins.

Application Control (D3-EAL: Executable Allowlisting): Where pos­si­ble, use ap­pli­ca­tion con­trol poli­cies to re­strict the in­stal­la­tion and ex­e­cu­tion of un­ap­proved com­mu­nity plu­g­ins in ap­pli­ca­tions like Obsidian.

Network Monitoring (D3-NTA: Network Traffic Analysis): Monitor for un­usual DNS queries or di­rect IP con­nec­tions re­lated to blockchain ser­vices from end­points where such ac­tiv­ity is not ex­pected.

Mitigation

Vet Community Plugins: Be ex­tremely cau­tious when en­abling third-party or com­mu­nity-de­vel­oped plu­g­ins in any ap­pli­ca­tion. Only in­stall plu­g­ins from the of­fi­cial, trusted mar­ket­place and re­view their per­mis­sions.

Disable Auto-Sync for Untrusted Vaults: Do not en­able plu­gin syn­chro­niza­tion when con­nect­ing to an Obsidian vault from an un­known or un­trusted source.

Principle of Least Privilege: Run ap­pli­ca­tions like Obsidian as a stan­dard user, not with ad­min­is­tra­tive priv­i­leges, to limit the po­ten­tial im­pact of a com­pro­mise.

Endpoint Security: Ensure up-to-date EDR and an­tivirus so­lu­tions are de­ployed to de­tect and block sus­pi­cious script ex­e­cu­tion and process in­jec­tion tech­niques.

You Need AI That Reduces Maintenance Costs

www.jamesshore.com

I’ll get straight to the point: your AI cod­ing agent, the one you use to write code, needs to re­duce your main­te­nance costs. Not by a lit­tle bit, ei­ther. You write code twice as quick now? Better hope you’ve halved your main­te­nance costs. Three times as pro­duc­tive? One third the main­te­nance costs. Otherwise, you’re screwed. You’re trad­ing a tem­po­rary speed boost for per­ma­nent in­den­ture.

Oh, you want to know why? Sure. Let’s go for a drive. On a dark desert high­way…

Productivity is Determined by Maintenance Costs

Every line of code you write has to be main­tained: bug fixes, cleanup, de­pen­dency up­grades, and so forth. I’m not talk­ing about new fea­tures or en­hance­ments. Just main­te­nance. For every month you spend writ­ing code, you’ll spend some amount of time in the fol­low­ing year main­tain­ing that code, and some in each year af­ter that, for­ever, as long as that code ex­ists.

Let’s say you asked a crowd of, say, 50 de­vel­op­ers what those main­te­nance costs were. Using a tech­nique called Wisdom of the Crowd, you could get a rea­son­ably ac­cu­rate re­sponse.1

1You’re wel­come to con­duct your own wis­dom-of-the-crowd sur­vey! But it turns out that the spe­cific num­bers don’t mat­ter for the over­all point I’m mak­ing here.

Your crowd might tell you that, for each month you spend writ­ing code, you’ll spend…

10 days on main­te­nance in the first year; and

10 days on main­te­nance in the first year; and

5 days on main­te­nance each year af­ter that.

5 days on main­te­nance each year af­ter that.

If you were a par­tic­u­larly ob­ses­sive in­di­vid­ual, you could spend hours mak­ing a spread­sheet mod­el­ing how those es­ti­mates af­fect pro­duc­tiv­ity over time. A spread­sheet like this.

The first month of a new pro­ject is glo­ri­ous. You spend all your time build­ing fancy new fea­tures.

The next month is slightly less glo­ri­ous. A frac­tion of your time—not much, but a smidge—goes to fix­ing bugs and clean­ing up de­sign mis­takes from the first month. In the third month, a smidge more. And the fourth month, the fifth, the sixth…

Eventually, it’s not glo­ri­ous at all. According to our crowd’s main­te­nance es­ti­mates, you’ll spend more than half your time on main­te­nance af­ter years. After ten years, you can hardly do any­thing else.

Halving the crowd’s main­te­nance es­ti­mates gives you three more years be­fore you hit the 50% mark. Doubling them sees you be­low 50% in less than a year.

The les­son is clear. If you want a pro­duc­tive team, you have to fo­cus on their main­te­nance costs.

All Models Are Wrong

Do these num­bers ring true to you? They do to me. In my ca­reer as a con­sul­tant, I spe­cial­ized in late-stage star­tups, and they all had the ex­act prob­lem shown in the graph above. About 5 – 9 years in, they’d no­tice their teams were no longer get­ting shit done, and then they’d call me.

Their teams weren’t quite as bad as the graph shows. Maybe their main­te­nance costs were lower. Or maybe… and this feels more likely to me… their main­te­nance costs were ex­actly that bad, and they pa­pered over the prob­lem in­stead. Maybe they:

Decided not to fix every bug, or up­grade every de­pen­dency

Decided not to fix every bug, or up­grade every de­pen­dency

Added peo­ple when the team got slow… and then kept adding more, be­cause it was never enough

Added peo­ple when the team got slow… and then kept adding more, be­cause it was never enough

Scrapped it all and started over with a rewrite

Scrapped it all and started over with a rewrite

There’s room to de­bate the pre­cise main­te­nance num­bers, but over­all, the model feels right. If you’ve been around the block, you know this graph is true. You’ve seen how pro­duc­tiv­ity melts away over time. You have the scars.

What Does This Have to Do With AI?

Only every­thing.

Let’s say your team just started us­ing Rock Lobster, the lat­est and great­est agen­tic cod­ing frame­work, and it Doubles!! your code out­put! Woohoo! The code’s a bit harder to un­der­stand, though, and your team is drown­ing in pull re­quests, and you maybe kinda sorta teensy weensy don’t ac­tu­ally read the code be­fore smash­ing the ap­prove but­ton. Like, at all. I mean, you skimmed it, dur­ing bor­ing meet­ings, some­times, and that’s gotta be good enough, right? LGTM, let’s get this shit done!

So now you’re pro­duc­ing two months of work in a month, and let’s say you’ve dou­bled how much each month” of out­put costs to main­tain. Next mon­th’s main­te­nance costs quadru­ple.

Oh.

About five months af­ter you start us­ing Rock Lobster, your pro­duc­tiv­ity is back down to where you started, and a few months af­ter that, it’s worse than it would have been had you never touched Rock Lobster in the first place.

I’m not say­ing your AI dou­bles main­te­nance costs. Or pro­duc­tiv­ity. This is an ex­treme ex­am­ple. But even if your AI pro­duces code that’s just as easy to main­tain as your hu­man-writ­ten code, the pro­duc­tiv­ity gains don’t last.

You Can Check Out Any Time You Like2

2But you can never leave.

Agents are ex­pen­sive, and they’re only get­ting more so. Once your agen­t’s juice is no longer worth the squeeze, you might de­cide to save your pen­nies and go back to cod­ing the old way. Like a cave­man. With your fin­gers.

Ha! Joke’s on you! When you stop us­ing the agent, all the pro­duc­tiv­ity ben­e­fit goes away… but the added main­te­nance costs don’t! As long as that code’s still around, you’re stuck with lower pro­duc­tiv­ity than if you had never touched the agent at all.

The Passage Back

The math only works if the LLM de­creases your main­te­nance costs, and by ex­actly the in­verse of the rate it adds code. If you dou­ble your out­put and your cost of main­tain­ing that out­put, two times two means you’ve quadru­pled your main­te­nance costs. If you dou­ble your out­put and hold your main­te­nance costs steady, two times one means you’ve still dou­bled your main­te­nance costs.

Instead, you have to in­vert your pro­duc­tiv­ity. If you’re pro­duc­ing twice as much code, you need code that costs half as much to main­tain. Three times as much code, one third the main­te­nance.

This is the se­cret to suc­cess. All the ben­e­fits, none of the lock-in.

Can We Kill the Beast?

I dunno. All my read­ing of the finest news sources says that cod­ing agents in­crease main­te­nance costs. Some peo­ple do say they help them un­der­stand large sys­tems bet­ter. But big de­creases in costs, of the size we need to see? No. Just the op­po­site.

That’s a prob­lem. The model is­n’t a per­fect rep­re­sen­ta­tion of re­al­ity, but the over­all mes­sage is right. You need AI that re­duces your main­te­nance costs, and in pro­por­tion to the speed boost you get from new code. Without it, you’re screwed. You’re trad­ing a tem­po­rary speed boost for per­ma­nent in­den­ture.

So, yeah, go ahead, chase im­prove­ments to your cod­ing speed. But spend just as much time chas­ing im­prove­ments to your main­te­nance costs. Or you, too, will be trapped in Hotel California.

Such a lovely place.

Such a lovely face.

As much as it might seem like it, this is­n’t meant to be an anti-AI rant. There’s other levers to pull, such as AI that makes main­te­nance it­self more pro­duc­tive, even if it does­n’t make the code more main­tain­able. I en­cour­age you to copy the spread­sheet and play with all the levers in the model. See what hap­pens when you change the as­sump­tions to match your real-world sit­u­a­tion.

The Greatest Shot in Television: Science Historian James Burke Had One Chance to Nail This Scene … and Nailed It

www.openculture.com

in Science, Technology, Television | October 4th, 2024 3 Comments

The 80-sec­ond clip above cap­tures a rock­et launch, some­thing of which we’ve all seen footage at one time or anoth­er. What makes its view­ers call it the great­est shot in tele­vi­sion” still to­day, 45 years af­ter it first aired, may take more than one view­ing to no­tice. In it, sci­ence his­to­ri­an James Burke speaks about how cer­tain gas­es ig­nite, and that the ther­mos flask per­mits you to store vast quan­ti­ties of those gas­es safe­ly, in their frozen liq­uid form, un­til you want to ig­nite them.” Use a suf­fi­cient­ly large flask filled with hydro­gen and oxy­gen, de­sign it to mix the gas­es and set light to them, and you get that” — that is, you get the rock­et that launch­es be­hind Burke just as soon as he points to it.

One can only ad­mire Burke’s com­po­sure in dis­cussing such tech­ni­cal mat­ters in a shot that had to be per­fect­ly timed on the first and only take. What you would­n’t know un­less you saw it in con­text is that it also comes as the fi­nal, cul­mi­nat­ing mo­ment of a 50-minute explana­to­ry jour­ney that be­gins with cred­it cards, then makes its way through the inven­tion of every­thing from a knight’s ar­mor to canned food to air con­di­tion­ing to the Sat­urn V rock­et, which put man on the moon.

For­mal­ly speak­ing, this was a typ­i­cal episode of Con­nec­tions, Burke’s 1978 tele­vi­sion se­ries that traces the most impor­tant and sur­pris­ing moves in the evo­lu­tion of sci­ence and tech­nol­o­gy through­out hu­man his­to­ry.

Though not as wide­ly remem­bered as Carl Sagan’s slight­ly lat­er Cos­mos, Con­nec­tions bears re­peat view­ing here in the twen­ty-first cen­tu­ry, not least for the intel­lec­tu­al and visu­al brava­do typ­i­fied by this great­est shot in tele­vi­sion,” now viewed near­ly 18 mil­lion times on Youtube. Watch it enough times your­self, and you’ll no­tice that it also pulls off some mi­nor sleight of hand by hav­ing Burke walk from a non-time-sen­si­tive shot into anoth­er with the al­ready-framed rock­et ready for liftoff. But that hard­ly lessens the feel­ing of achieve­ment when the launch comes off. Des­ti­na­tion: the moon, or Moscow,” says Burke, the plan­ets, or Peking” — a clos­ing line that sound­ed con­sid­er­ably more dat­ed a few years ago than it does to­day.

Relat­ed Con­tent:

Endeavour’s Launch Viewed from Boost­er Cam­eras

The 100 Most Mem­o­rable Shots in Cin­e­ma Over the Past 100 Years

The Most Beau­ti­ful Shots in Cin­e­ma His­to­ry: Scenes from 100+ Films

125 Great Sci­ence Videos: From Astron­o­my to Physics & Psy­chol­o­gy

Based in Seoul, Col­in Marshall writes and broad­casts on cities, lan­guage, and cul­ture. His pro­jects in­clude the Sub­stack newslet­ter Books on Cities and the book The State­less City: a Walk through 21st-Cen­tu­ry Los Ange­les. Fol­low him on Twit­ter at @col­in­mar­shall or on Face­book.

The cuda-oxide Book — cuda-oxide

nvlabs.github.io

cuda-ox­ide is an ex­per­i­men­tal Rust-to-CUDA com­piler that lets you write (SIMT) GPU ker­nels in safe(ish), id­iomatic Rust. It com­piles stan­dard Rust code di­rectly to PTX — no DSLs, no for­eign lan­guage bind­ings, just Rust.

Note

This book as­sumes fa­mil­iar­ity with the Rust pro­gram­ming lan­guage, in­clud­ing own­er­ship, traits, and gener­ics. Later chap­ters on async GPU pro­gram­ming also as­sume work­ing knowl­edge of async/.​await and run­times like tokio.

For a re­fresher, see The Rust Programming Language, Rust by Example, or the Async Book.

Project Status#

The v0.1.0 re­lease is an early-stage al­pha: ex­pect bugs, in­com­plete fea­tures, and API break­age as we work to im­prove it. We hope you’ll try it and help shape its di­rec­tion by shar­ing feed­back on your ex­pe­ri­ence.

🚀 Quick start#

use cu­d­a_de­vice::{cu­d­a_­mod­ule, ker­nel, thread, DisjointSlice}; use cu­d­a_­core::{Cu­d­a­Con­text, DeviceBuffer, LaunchConfig};

#[cuda_module] mod ker­nels { use su­per::*;

#[kernel] fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) { let idx = thread::in­dex_1d(); let i = idx.get(); if let Some(c_elem) = c.get_­mut(idx) { *c_elem = a[i] + b[i]; } } }

fn main() { let ctx = CudaContext::new(0).unwrap(); let stream = ctx.de­fault­_stream(); let mod­ule = ker­nels::load(&ctx).un­wrap();

let a = DeviceBuffer::from_host(&stream, &[1.0f32; 1024]).unwrap(); let b = DeviceBuffer::from_host(&stream, &[2.0f32; 1024]).unwrap(); let mut c = DeviceBuffer::<f32>::zeroed(&stream, 1024).unwrap();

mod­ule .vecadd(&stream, LaunchConfig::for_num_elems(1024), &a, &b, &mut c) .unwrap();

let re­sult = c.to_host_vec(&stream).un­wrap(); as­sert_eq!(re­sult[0], 3.0); }

Build and run with cargo ox­ide run vecadd upon in­stalling the pre­req­ui­sites.

Note

#[cuda_module] em­beds the gen­er­ated de­vice ar­ti­fact into the host bi­nary and gen­er­ates a typed ker­nels::load func­tion plus one launch method per ker­nel. The lower-level load­_k­er­nel_­mod­ule and cu­d­a_launch! APIs re­main avail­able when you need to load a spe­cific side­car ar­ti­fact or build cus­tom launch code.

Why cuda-ox­ide?#

🦀 Rust on the GPU

Write GPU ker­nels with Rust’s type sys­tem and own­er­ship model. Safety is a first-class goal, but GPUs have sub­tleties — read about the safety model.

💎 A SIMT Compiler

Not a DSL. A cus­tom rustc code­gen back­end that com­piles pure Rust to PTX.

⚡ Async Execution

Compose GPU work as lazy DeviceOperation graphs. Schedule across stream pools. Await re­sults with .await.

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.

Visit pancik.com for more.