[{"data":1,"prerenderedAt":1508},["ShallowReactive",2],{"home:posts":3,"home:categories":1466},[4,85,343,491,727,803,860,1268,1343],{"id":5,"title":6,"body":7,"category_label":70,"category_slug":71,"date_created":72,"dek":73,"description":64,"directus_id":74,"extension":75,"is_promoted":76,"meta":77,"navigation":78,"path":79,"published_at":72,"seo":80,"slug":81,"status":82,"stem":83,"__hash__":84},"posts\u002Fposts\u002F2026-05-31-the-prompt-i-never-refactor.md","The Most Annoying Prompt Is the One I Never Refactor",{"type":8,"value":9,"toc":63},"minimark",[10,15,29,32,36,43,46,50,57,60],[11,12,14],"h2",{"id":13},"i-spent-all-night-judging-another-devs-accretion","I spent all night judging another dev's accretion",[16,17,18,19,23,24,28],"p",{},"The repo was a museum of solo-project decisions nobody ever revisited. A 1760-line bash TUI to manage n8n environments. Five ",[20,21,22],"code",{},"GEMINI.md"," files, four describing a stack that had moved on months ago. A pre-commit hook that goes red when Prettier is merely ",[25,26,27],"em",{},"unhappy",", not when a human is actually needed. Workflow exports that churn version GUIDs on every save, so you can't tell a real change from noise.",[16,30,31],{},"None of it malicious. All of it earnest. Just never cleaned. I had a name for it by midnight: tribal accretion without a cleanup pass. You build for the version of the project that existed when you started, and you never go back, because going back isn't a feature.",[11,33,35],{"id":34},"then-it-bit-me","Then it bit me",[16,37,38,39,42],{},"The agent kept refusing to push a commit until I asked explicitly. Annoying-funny. I asked where the rule even came from. The answer was ",[25,40,41],{},"me",". My own global instructions — a line I wrote back when I was learning to code with Claude: \"no destructive actions, don't push every time we change a file.\" Except those are two completely different risk classes welded into one sentence. Written for one version of the model. Carried through the next era's \"be more explicit\" panic. Now read by the current one. Compounded across three generations and never once refactored.",[16,44,45],{},"I don't prompt, I discuss. But the instruction file is the most impactful prompt I have. And it's the one artifact I treat as write-once.",[11,47,49],{"id":48},"the-lesson","The lesson",[16,51,52,53,56],{},"I refactor code for a living. I have opinions about a stranger's ",[20,54,55],{},"run.sh",". And the highest-leverage text in my entire workflow — the standing instructions that shape every session — I let rot exactly the way I just spent a night mocking.",[16,58,59],{},"The prompt is code. The instruction file is a codebase. It accretes, it conflates concerns, it drifts across generations, and it earns a cleanup pass like anything else. I never gave it one, because maintaining your tools feels like not-working.",[16,61,62],{},"Split the conflated rule. Safety stays strict. Routine git in trusted repos gets standing authorization. And put a recurring reminder on the calendar to re-read the thing that reads me.",{"title":64,"searchDepth":65,"depth":65,"links":66},"",2,[67,68,69],{"id":13,"depth":65,"text":14},{"id":34,"depth":65,"text":35},{"id":48,"depth":65,"text":49},"Craft","craft","2026-05-31T01:48:39.163Z","I spent a night judging another developer's uncleaned repo. Then I found the same rot in my own global instructions — a rule written three model generations ago, never once refactored.","a45cf06b-12f7-481e-8d21-0a2010b6bc4b","md",false,{},true,"\u002Fposts\u002F2026-05-31-the-prompt-i-never-refactor",{"title":6,"description":64},"2026-05-31-the-prompt-i-never-refactor","published","posts\u002F2026-05-31-the-prompt-i-never-refactor","L429G76yoeXoJKe-YnNSCXepEfDRov5sXOpWh8QlUmc",{"id":86,"title":87,"body":88,"category_label":332,"category_slug":333,"date_created":334,"dek":335,"description":64,"directus_id":336,"extension":75,"is_promoted":76,"meta":337,"navigation":78,"path":338,"published_at":334,"seo":339,"slug":340,"status":82,"stem":341,"__hash__":342},"posts\u002Fposts\u002Fquarterly-k8s-migration-is-a-tuesday-night.md","The quarterly K8s migration is now a Tuesday night",{"type":8,"value":89,"toc":324},[90,94,102,105,108,112,115,137,140,144,151,154,158,161,164,223,227,230,290,297,301,308,318,321],[11,91,93],{"id":92},"the-thesis","The thesis",[16,95,96,97,101],{},"Production K8s migrations (the real ones, with stateful data and live customer traffic) are ",[98,99,100],"strong",{},"evening-tier work in 2026",", not quarter-tier projects. Most engineering orgs haven't updated their mental model. They're still scheduling \"infrastructure modernization initiatives\" with kickoff decks, weekly syncs, and a target completion of \"end of next quarter.\" Then they wonder why nothing actually moves.",[16,103,104],{},"Tonight we moved 38 pods, ~150 GB of state, an entire ES cluster (including its master quorum), and an ingress's worth of traffic across two AZs onto storage that didn't exist on those nodes 36 hours ago. With 13 minutes of outage. From a French ISP-grade home setup, with a CTO who said \"go faster, I'm taking the risk\" and a Claude Code window.",[16,106,107],{},"This is what tooling has done for us. People should know.",[11,109,111],{"id":110},"what-we-actually-did","What we actually did",[16,113,114],{},"Evening of 2026-05-05 → morning of 2026-05-06:",[116,117,118,125,131],"ul",{},[119,120,121,124],"li",{},[98,122,123],{},"Stage 2",", burn-in environment cutover to the new nodes. 9 pods. Validated the storage path and the compute uplift before touching prod.",[119,126,127,130],{},[98,128,129],{},"Stage 3",", production application (the API, the queues, redis, the FTP intake). 23 pods. 4 phases (stateless → redis → import-ftp → re-enable scheduled imports). 3 minutes of customer outage during the redis cutover, the only window where we couldn't roll.",[119,132,133,136],{},[98,134,135],{},"Stage 4",", Elasticsearch. 6 nodes restructured (legacy 3-data + 2-master + 1-transform on Longhorn → 2-data + 2-master + 1-voting_only + 1-transform on LINSTOR with daily S3 snapshots). 10 minutes of customer outage from a stale env-var oversight.",[16,138,139],{},"Replicas, replicated storage, S3 backups, anti-affinity, voting-only tiebreaker on a tiny VM in another AZ. The whole shape of \"how a real prod cluster looks.\" Done in an evening. Walked back into the room the next morning, dashboards green, channel quiet.",[11,141,143],{"id":142},"the-compute-claim","The compute claim",[16,145,146,147,150],{},"Mid-migration, on a real workload (a 63 MB XML import that fans out into 24,000 child jobs across 6 Horizon workers), the new nodes processed it ",[98,148,149],{},"5.7× faster per job"," than the equivalent on legacy. 58 jobs\u002Fsec vs 10 jobs\u002Fsec, same code, same Redis, same Postgres. Just newer silicon and proper local-NVMe-backed DRBD instead of whatever the legacy storage was doing.",[16,152,153],{},"That number alone justifies the migration. Doing it on a Tuesday night justifies stopping the meeting.",[11,155,157],{"id":156},"what-made-it-possible","What made it possible",[16,159,160],{},"It wasn't the execution. The execution was just typing the script. That's the whole point.",[16,162,163],{},"It was:",[165,166,167,173,195,217],"ol",{},[119,168,169,172],{},[98,170,171],{},"Two months of paranoid planning."," Every stage, patch file, and cutover sequence on paper. The outage windows pre-budgeted. The rollback steps documented. By the time we ran a command tonight, we'd already played the move in our heads four or five times. Planning is the bottleneck, not execution. Always was. Tooling just made execution cheap enough that the planning effort actually pays off.",[119,174,175,178,179,182,183,186,187,190,191,194],{},[98,176,177],{},"The runbook structure."," Every destructive step lived in a script under ",[20,180,181],{},"infra\u002Ftmp\u002F"," (one-shot) or ",[20,184,185],{},"infra\u002Fclusters\u002Fprod\u002F"," (canonical \u002F reproducible). Idempotent. Re-runnable. When the first containerd-move script aborted halfway because ",[20,188,189],{},"k8s-agent.service"," didn't exist (it was ",[20,192,193],{},"kubelet.service","), I just edited the failed step and re-ran. Recovery time: 30 seconds. Not \"schedule a follow-up call.\"",[119,196,197,200,201,204,205,208,209,212,213,216],{},[98,198,199],{},"The cutover tricks."," The cleanest one tonight was for the redis migration. Standard playbook says: BGSAVE, dump.rdb out, delete the old PVC, recreate on new storage, copy dump.rdb in, start redis. The race is the gap between ",[20,202,203],{},"kubectl apply"," (which scales redis up) and your manual ",[20,206,207],{},"scale --replicas=0"," (which stops it before it overwrites your dump.rdb with empty data). My CTO suggested overriding the redis container's command to ",[20,210,211],{},"sleep 2d"," for the duration of the data restore. Pod runs, mounts PVC, doesn't run redis, can't write to disk. We ",[20,214,215],{},"kubectl cp"," the data in, then re-apply with the real command. Race eliminated. The kind of move you can only see if you understand both the system AND the orchestrator's idempotency model.",[119,218,219,222],{},[98,220,221],{},"The CTO who took the risk."," Originally this was supposed to be a 48-72-hour burn-in followed by a careful prod cutover spread over a week. He looked at the data after 4 hours and said \"go faster, I'm taking responsibility.\" That is the rarest thing in engineering management: someone who reads the signals and writes \"go\" in the chat. Without that, this is still a quarterly project. With that, it's tonight.",[11,224,226],{"id":225},"what-surprised-us","What surprised us",[16,228,229],{},"The surprises tonight, none of which broke us:",[116,231,232,254,268],{},[119,233,234,237,238,241,242,245,246,249,250,253],{},[98,235,236],{},"DEV1-M comes with a 9 GB root disk, not the 50 GB I'd assumed during planning."," Containerd images alone trip kubelet's ",[20,239,240],{},"DiskPressure"," threshold under default eviction policy. The voting-only ES master couldn't schedule on the tiebreaker node. Fix: attach a 50 GB SBS volume, restructure as ",[20,243,244],{},"\u002Fmnt\u002Fsbs"," with bind mounts to ",[20,247,248],{},"\u002Fvar\u002Flib\u002Fcontainerd"," and ",[20,251,252],{},"\u002Fvar\u002Flog",". Discovered, fixed, documented in a runbook, committed. 90 minutes door-to-door. Three years ago this would have been a Slack thread that died after two days because nobody could agree on the right approach.",[119,255,256,263,264,267],{},[98,257,258,259,262],{},"Bitnami pulled ",[20,260,261],{},"bitnami\u002Fredis:8.0"," from Docker Hub silently sometime in August 2025",", as part of their licensing changes. Our prod redis was running on a cached image. The moment it ever restarted, it was dead. We caught this in Stage 2 burn-in (where the image had to pull fresh on a new node) and switched to ",[20,265,266],{},"bitnamilegacy\u002Fredis:8.0",". It's dumb luck that this didn't blow up production three months ago.",[119,269,270,273,274,277,278,281,282,285,286,289],{},[98,271,272],{},"ECK auto-deletes per-nodeSet headless services when you remove a nodeSet."," Our prod API was hardcoded to ",[20,275,276],{},"search-es-es-data.elasticsearch.svc",", the headless service of the legacy data nodeSet. When Stage 4 removed that nodeSet, ECK deleted the service. The public site's ",[20,279,280],{},"\u002Facheter\u002F*"," routes started returning 500. 10 minutes of customer outage. Switched to the cluster-wide LB service ",[20,283,284],{},"search-es-es-http.elasticsearch.svc",", rolled the API pods, recovered. ",[25,287,288],{},"Never reference per-nodeSet services from app config."," Now permanent in my head, and in the recap doc.",[16,291,292,293,296],{},"These are the kind of things you only learn by doing it. The kind of things people who've never done a real migration don't know they don't know. The kind of things that ",[25,294,295],{},"would"," eat a quarter, if you let them.",[11,298,300],{"id":299},"the-ceiling-moved","The ceiling moved",[16,302,303,304,307],{},"Most engineering orgs are still in the \"infrastructure modernization is a quarterly initiative\" mental model. They have a Confluence page. They have a Q3 OKR. They have a Slack channel called ",[20,305,306],{},"#infra-modernization-2026"," that gets one message a week.",[16,309,310,311,313,314,317],{},"The actual ceiling moved. Container Storage Interface drivers are stable. Operators (ECK, Piraeus, etc.) handle the orchestration that used to need humans (shard drains, voting-config exclusions, PVC binding races). S3 snapshots are free real estate. Kustomize gives you patches that compose. ",[20,312,215],{}," works through a tar pipe and is fast enough for any data volume that fits in your ",[20,315,316],{},"dump.rdb",".",[16,319,320],{},"If you've been running production K8s for three years, you have all the components. You just need the planning discipline and the runbook structure, plus a CTO who reads the signals. Then it's an evening.",[16,322,323],{},"Mine took 13 minutes of outage. Yours might take 30. It's still a Tuesday.",{"title":64,"searchDepth":65,"depth":65,"links":325},[326,327,328,329,330,331],{"id":92,"depth":65,"text":93},{"id":110,"depth":65,"text":111},{"id":142,"depth":65,"text":143},{"id":156,"depth":65,"text":157},{"id":225,"depth":65,"text":226},{"id":299,"depth":65,"text":300},"Build Log","build-log","2026-05-06T01:07:20.191Z","38 pods, ~150 GB of state, and an Elasticsearch cluster moved across two AZs in one evening, with 13 minutes of outage. The execution was never the bottleneck. Two months of planning was.","31992263-3014-46c1-b5eb-81697814192e",{},"\u002Fposts\u002Fquarterly-k8s-migration-is-a-tuesday-night",{"title":87,"description":64},"quarterly-k8s-migration-is-a-tuesday-night","posts\u002Fquarterly-k8s-migration-is-a-tuesday-night","IYtXuzngSb7PnXU1LdWXE95wdB5sPyjLQyvEedHVaBQ",{"id":344,"title":345,"body":346,"category_label":480,"category_slug":481,"date_created":482,"dek":483,"description":64,"directus_id":484,"extension":75,"is_promoted":78,"meta":485,"navigation":78,"path":486,"published_at":482,"seo":487,"slug":488,"status":82,"stem":489,"__hash__":490},"posts\u002Fposts\u002Fharnesses-matter-as-much-as-models.md","Your harness is half the model",{"type":8,"value":347,"toc":475},[348,366,370,373,376,395,440,443,447,462,466,469,472],[349,350,351],"blockquote",{},[16,352,353,354,357,358,361,362,365],{},"I was cleaning up the scratch script I used to draft this post (one ",[20,355,356],{},"rm \u002Ftmp\u002Fpush-raw-posts.py",") and the subprocess hung on ",[20,359,360],{},"remove regular file '\u002Ftmp\u002Fpush-raw-posts.py'?",". The exact ",[20,363,364],{},"rm -i"," contamination the post is about. The recursion is too clean to leave alone.",[11,367,369],{"id":368},"the-harness-is-not-a-shell-around-the-model","The harness is not a shell around the model",[16,371,372],{},"I thought the harness was a shell around the model. Type prompt, get output, done. The model writes the code, the harness is plumbing.",[16,374,375],{},"Running an actual benchmark with four coder-bricks through their officially-recommended harnesses disabused me of that in the worst way. MiniMax via Claude Code (MiniMax's own first-recommended path, Anthropic-compat endpoint, \"just set ANTHROPIC_BASE_URL and you're done\" per the docs) gave wall-time blowups of 100×. A task that should have taken 107 seconds took 10,682.",[16,377,378,379,382,383,386,387,390,391,394],{},"Root cause was maximally unglamorous. Claude Code's tool-use subprocess sources the parent shell's interactive snapshot. On my Fedora + prezto setup, that snapshot re-establishes ",[20,380,381],{},"alias rm='nocorrect rm -i'",". Model-issued ",[20,384,385],{},"rm \u003Cexisting> && cat > \u003Csame>"," tool calls (a very common pattern for rewriting test files) then block forever on the ",[20,388,389],{},"-i"," confirmation prompt. The subprocess captures stdout and stderr but doesn't route stdin back, so the prompt hangs indefinitely. ",[20,392,393],{},"--bare"," mode doesn't disable shell-snapshot loading. It only gates CLAUDE.md, hooks, plugin sync, and keychain reads.",[16,396,397,398,401,402,405,406,409,410,409,413,409,416,419,420,423,424,409,427,409,430,409,433,409,436,439],{},"The fix is an operational contract. Strip all ",[20,399,400],{},"ANTHROPIC_*"," env vars from the subprocess, strip ",[20,403,404],{},"CLAUDE_CODE_OAUTH_TOKEN"," to avoid credential leaks, set ",[20,407,408],{},"SHELL=\u002Fbin\u002Fbash",", ",[20,411,412],{},"BASH_ENV=\u002Fdev\u002Fnull",[20,414,415],{},"ENV=\u002Fdev\u002Fnull",[20,417,418],{},"ZDOTDIR=\u003Cfresh empty dir>",", and (here's the fun one) set all five ",[20,421,422],{},"ANTHROPIC_*_MODEL"," aliases (",[20,425,426],{},"MODEL",[20,428,429],{},"DEFAULT_OPUS_MODEL",[20,431,432],{},"DEFAULT_SONNET_MODEL",[20,434,435],{},"DEFAULT_HAIKU_MODEL",[20,437,438],{},"SMALL_FAST_MODEL",") to the same value, because Claude Code's internal Opus\u002FSonnet\u002FHaiku routing otherwise breaks with \"unknown model.\"",[16,441,442],{},"None of that is in the official setup guide. You find it by running your own benchmark.",[11,444,446],{"id":445},"sibling-surprise","Sibling surprise",[16,448,449,450,453,454,457,458,461],{},"Cline CLI 2.0 went headless in February 2026. I missed it by two months in my research and confidently wrote that \"Cline is VS Code only, DS-via-Cline from an HL session isn't viable.\" It is viable. ",[20,451,452],{},"-y"," for yolo, ",[20,455,456],{},"--json"," for structured output, scoped ",[20,459,460],{},"--config"," dir so you don't pollute the user's IDE state. The second-biggest harness ecosystem in the Anthropic-adjacent world added headless mode and I hadn't noticed. Nobody I'd read had noticed either. The earlier writeups I'd scraped were still pitching the VS Code framing.",[11,463,465],{"id":464},"two-lessons-same-insight","Two lessons, same insight",[16,467,468],{},"First: an official harness recommendation is where you start. The company that made the model picks the harness that shows their model at its best. They don't necessarily pick the harness that runs without contamination on your specific dev box. The gap between \"vendor says works\" and \"actually works on my machine\" is where hours go.",[16,470,471],{},"Second: the harness moves your numbers, and your model capability comparison will credit the movement to the wrong variable. If I'd compared MiniMax to Qwen3.6 based on wall time alone, with that 100× contamination un-caught, I'd have concluded MM is impossibly slow. It isn't. My environment was making it wait on an interactive shell prompt that should never have existed.",[16,473,474],{},"You catch this by running your own benchmark against your own infra. Not someone else's SWE-bench numbers or the vendor's marketing deck. Your tasks, your harness, your subprocess, your shell. That's where the operational contract writes itself.",{"title":64,"searchDepth":65,"depth":65,"links":476},[477,478,479],{"id":368,"depth":65,"text":369},{"id":445,"depth":65,"text":446},{"id":464,"depth":65,"text":465},"Skeptic's Toolbox","skeptics-toolbox","2026-04-21T00:27:58.944Z","I ran four coder models through their officially-recommended harnesses and one came out 100x slower. The cause was my shell's rm -i alias leaking into Claude Code's tool subprocess. Your model comparison will credit that slowdown to the wrong variable.","1f690bb4-436a-4ddb-a080-607f30465052",{},"\u002Fposts\u002Fharnesses-matter-as-much-as-models",{"title":345,"description":64},"harnesses-matter-as-much-as-models","posts\u002Fharnesses-matter-as-much-as-models","lV1MvQW9v6oEPIHq-7PD5nhALaGpO88Vb8HdWkqU4jU",{"id":492,"title":493,"body":494,"category_label":716,"category_slug":717,"date_created":718,"dek":719,"description":64,"directus_id":720,"extension":75,"is_promoted":78,"meta":721,"navigation":78,"path":722,"published_at":718,"seo":723,"slug":724,"status":82,"stem":725,"__hash__":726},"posts\u002Fposts\u002Fsft-learns-your-median-employee.md","SFT Learns Your Median Employee, Not Your Best One",{"type":8,"value":495,"toc":708},[496,504,507,510,514,517,520,523,526,529,532,536,539,542,545,548,552,555,569,572,576,579,582,585,588,591,599,602,605,608,612,615,618,621,624,628,705],[349,497,498],{},[16,499,500,503],{},[98,501,502],{},"How this post was written."," I wrote the source draft. Four models each rewrote it from that same draft plus my persona files (writer, experimental, operational): Claude Opus 5, GPT-5.6 Sol, Kimi K3 (low reasoning effort), GLM 5.2. I judged the four blind, labels shuffled per post, model names revealed only after the verdict. This is the Claude Opus 5 version, which won. French phrases the models dropped in my voice were translated back to English; the quoted French system-prompt lines are the real ones. On 2026-08-10 the same winning model rewrote it once more from the same source, with regenerated persona files and an AI-tell lint report on the first version in the brief.",[16,505,506],{},"Blind test, labels hidden until after I had picked: the fine-tune lost to its own base model, 92% to 8%. Same prompts, every metric worse. No debate possible.",[16,508,509],{},"Nothing in the training run had warned me. Loss curves textbook, convergence clean, the whole thing healthy right up to the moment I looked at what it had converged to.",[11,511,513],{"id":512},"what-4000-conversations-average-out-to","What 4,000 conversations average out to",[16,515,516],{},"4,000 real customer service conversations. Qwen3-8B-Instruct as the base. LoRA at the hyperparameters everyone starts with, all of them in the table at the bottom.",[16,518,519],{},"SFT converges to the median of your dataset. Every answer in there gets one vote, the excellent ones and the throwaway ones alike.",[16,521,522],{},"My 4,000 conversations included every operator response ever sent, from the excellent ones down to the \"here is a generic search link, good luck\" ones, with a lot of rushed and passable filling the middle. Run that through gradient descent and you get a portrait of the median operator. Short answers with a generic link attached. The client's request goes back unreformulated, and an emotional case gets the same flat treatment as a routine one.",[16,524,525],{},"Out of the box, Qwen3-8B-Instruct is already a good chatbot. It reformulates the request and structures the answer. On an emotional message it says something human before it says something useful.",[16,527,528],{},"So the fine-tune worked. It transferred what I handed it, and what I handed it was the average of a support desk. I had signed off on the dataset.",[16,530,531],{},"The model learned to sound like an average employee. The star performer was in there too, weighted exactly like everyone else.",[11,533,535],{"id":534},"the-fabrications-came-in-perfect-brand-voice","The fabrications came in perfect brand voice",[16,537,538],{},"\"100EUR for a 1-hour massage.\" \"The 2025 calendars are open for most properties.\" Both fabricated, both stated with total confidence, in the tone I had just finished training.",[16,540,541],{},"Human operators state a price confidently because they looked it up. The model saw thousands of confident factual statements and learned the shape of the confidence with none of the lookup behind it. People generate facts from knowledge. Models generate patterns from training data.",[16,543,544],{},"When the pattern says state a specific number with authority, the model states a specific number with authority. Whether the number exists was never a variable it had access to.",[16,546,547],{},"That is the failure mode to watch when you fine-tune on real operational data. You are teaching the posture of knowing, detached from any knowing.",[11,549,551],{"id":550},"a-thin-coat-instead-of-a-repaint","A thin coat instead of a repaint",[16,553,554],{},"v2 is four changes, and all four say the same thing to the optimizer: move less.",[116,556,557,560,563,566],{},[119,558,559],{},"Dataset: 4,115 examples down to 574. Tier 1 only, score 4 and above.",[119,561,562],{},"Learning rate: 2e-4 down to 5e-5.",[119,564,565],{},"LoRA rank: 16 down to 8. Less capacity, less room to absorb the bad patterns along with the good ones.",[119,567,568],{},"Epochs: 3 down to 1-2. On a small clean set, another pass is another chance to overwrite.",[16,570,571],{},"I am not training a chatbot from scratch. A competent one already exists, and I want it to speak with our accent. Capability comes from the base model. The LoRA adds the accent on top.",[11,573,575],{"id":574},"the-pink-elephant-in-the-system-prompt","The pink elephant in the system prompt",[16,577,578],{},"Rewriting the v2 system prompt turned up a second thing, unrelated on paper.",[16,580,581],{},"Negative instructions work badly on LLMs.",[16,583,584],{},"\"Ne JAMAIS inventer d'information.\" Sounds firm. It has the structure of telling a kid not to think of a pink elephant, and the first thing processed is the elephant. Cognitive science calls it Ironic Process Theory, and it maps onto token generation better than it has any right to.",[16,586,587],{},"Generation is a positive operation. The model selects a next token and has no move available for avoiding one. A negation pushes an unwanted output slightly down the distribution, while a direction pushes the wanted one up. That asymmetry is where a guardrail leaks.",[16,589,590],{},"Every rule got rewritten as a direction:",[116,592,593,596],{},[119,594,595],{},"\"Ne JAMAIS inventer d'information\" became \"TOUJOURS verifier une information avant de la communiquer. Si tu ne la connais pas, dis-le clairement.\" (always verify before you communicate, and say so plainly when you don't know)",[119,597,598],{},"\"Ne jamais ecrire comme si tu etais proprietaire\" became \"Parler en tant que plateforme qui met en relation voyageurs et hebergeurs.\" (speak as the platform connecting travelers and hosts)",[16,600,601],{},"Zero negations in the final prompt. Every line names an action to take.",[16,603,604],{},"Anthropic's own docs recommend this, and prompt-engineering circles have known it for a while. Production prompts ignore it anyway, mine included until this rewrite.",[16,606,607],{},"Both layers have to point the same way. The LoRA teaches tone. Guardrails live in the system prompt, and a guardrail phrased as a prohibition is a suggestion aimed at a mechanism that only knows how to move toward things.",[11,609,611],{"id":610},"a-dataset-audit-disguised-as-a-training-run","A dataset audit disguised as a training run",[16,613,614],{},"Your first fine-tune is a dataset quality audit wearing the costume of a training run.",[16,616,617],{},"I had read the data before training on it. It read fine. Real conversations, our own work, nothing that jumped out as broken. What reading could never show me was the distribution, and the model is the only reader that takes all 4,000 examples equally seriously.",[16,619,620],{},"Most ML work in production needs three to five iterations before anything is deployable. A first attempt that comes out perfect means luck, or a target too easy to be worth hitting.",[16,622,623],{},"The eval on v2 is still TBD. I am not writing the win before I have it.",[11,625,627],{"id":626},"numbers","Numbers",[629,630,631,646],"table",{},[632,633,634],"thead",{},[635,636,637,640,643],"tr",{},[638,639],"th",{},[638,641,642],{},"v1",[638,644,645],{},"v2",[647,648,649,661,672,683,694],"tbody",{},[635,650,651,655,658],{},[652,653,654],"td",{},"Dataset size",[652,656,657],{},"4,115",[652,659,660],{},"574",[635,662,663,666,669],{},[652,664,665],{},"Learning rate",[652,667,668],{},"2e-4",[652,670,671],{},"5e-5",[635,673,674,677,680],{},[652,675,676],{},"LoRA rank",[652,678,679],{},"16",[652,681,682],{},"8",[635,684,685,688,691],{},[652,686,687],{},"Epochs",[652,689,690],{},"3",[652,692,693],{},"1-2",[635,695,696,699,702],{},[652,697,698],{},"Eval result",[652,700,701],{},"8% win rate",[652,703,704],{},"TBD",[16,706,707],{},"Four thousand examples taught the model to be the average of a support desk. The 574 left are the ones that survived a quality score, and they are the first dataset I can say I looked at properly.",{"title":64,"searchDepth":65,"depth":65,"links":709},[710,711,712,713,714,715],{"id":512,"depth":65,"text":513},{"id":534,"depth":65,"text":535},{"id":550,"depth":65,"text":551},{"id":574,"depth":65,"text":575},{"id":610,"depth":65,"text":611},{"id":626,"depth":65,"text":627},"ML Journal","ml-journal","2026-04-10T20:14:53.883Z","4,000 real support conversations, textbook loss curves, and a fine-tune that lost to its own base model 92% to 8%. SFT converges to the median of your dataset, and the median operator writes short answers with generic links.","e88d84c2-2766-406f-986e-5a084ce9b26b",{},"\u002Fposts\u002Fsft-learns-your-median-employee",{"title":493,"description":64},"sft-learns-your-median-employee","posts\u002Fsft-learns-your-median-employee","KxykYwMHyYGWaCzpUnVOYOGf5CaI22t95iHNXajH7j0",{"id":728,"title":729,"body":730,"category_label":792,"category_slug":793,"date_created":794,"dek":795,"description":64,"directus_id":796,"extension":75,"is_promoted":76,"meta":797,"navigation":78,"path":798,"published_at":794,"seo":799,"slug":800,"status":82,"stem":801,"__hash__":802},"posts\u002Fposts\u002Fthe-gap-was-never-knowledge.md","The Gap Was Never Knowledge",{"type":8,"value":731,"toc":790},[732,739,742,745,748,751,754,757,760,763,766,769,772,775,778,781,784,787],[349,733,734],{},[16,735,736,738],{},[98,737,502],{}," I wrote the source draft. Four models each rewrote it from that same draft plus my persona files (writer, experimental, operational): Claude Opus 5, GPT-5.6 Sol, Kimi K3 (low reasoning effort), GLM 5.2. I judged the four blind, labels shuffled per post, model names revealed only after the verdict. This is the GLM 5.2 version, which won. The client's name is changed; the conversation is real. On 2026-08-10 the same winning model rewrote it once more from the same source, with regenerated persona files and an AI-tell lint report on the first version in the brief.",[16,740,741],{},"Nico opened with the most honest line I've heard anyone say about working with AI. Depressed one day because the numbers aren't there, over-excited the next because of what the tools will make possible tomorrow. I knew the feeling. I get the same whiplash between Claude Code sessions and my own bank account. The wider mood doesn't help. Three AI-risk videos in a row and you're done for the day.",[16,743,744],{},"He'd watched a Claude Code tutorial in his car. Some guy builds a complete activity dashboard from scratch. Nico almost cried. He's holding 400 Excel files together by hand and he knows it has to end. He told me he doesn't have the time, and he bookmarked the video anyway. The list of things AI could do for him was growing faster than he could touch any of it.",[16,746,747],{},"Three months of this had taught me one thing I keep having to relearn. Start. Drop one ugly first draft into a folder and leave it there, even untouched for two weeks. Carrying the thought that you should be doing this is heavier than any rough version you'd be embarrassed to show. One small win snaps the loop.",[16,749,750],{},"He'd already tried to clear his runway with Google Sites, WordPress, Netlify Drop, cloud storage buckets, and none of it took. So I asked Claude for the fastest path a non-developer could walk. It came back with a concrete answer. CC web for the work, with a GitHub repo and Vercel behind it. Free tier, fifteen minutes to set up, conversational after that. I forwarded the answer to Nico word for word.",[16,752,753],{},"Then the objections landed, and each one had already been answered in the message he was replying to.",[16,755,756],{},"He didn't want to pay for a tool he hadn't tried. The free tier was right there in the text. The terminal scared him, except there was no terminal. The whole thing ran in a browser, and that was in the text too. Could he lock it behind a password? That one, I told him, you ask CC.",[16,758,759],{},"His brain spent ten minutes rejecting answers that had been in front of him since the first message.",[16,761,762],{},"Then his reading caught up. \"Ah, when you say CC web, it runs in the cloud. Your recommendation was right from the start. I'm doing it tonight.\"",[16,764,765],{},"From \"I can't find the right workflow\" to \"I'm doing it tonight\" took ten minutes.",[16,767,768],{},"He kept going after that. Data privacy came up, then access control, then whether the dashboards would hold up. Same answer from me every time. Ask CC. Then I said the thing I'd been watching happen: almost every answer I'd given him over the last hour could have come straight from the tool I was pushing him toward. If he'd been on it already, he wouldn't have needed me for most of it.",[16,770,771],{},"I'd been writing the conversation up as it happened, so I told him. He wrote back, \"Lol, you bastard, I'm not a guinea pig.\"",[16,773,774],{},"Revealing that usually makes people perform. Nico dropped his guard instead, and the conversation got sharper. He pushed back on my framing. I'd called what he was doing resistance to change. He corrected me: in transition. The word matters, and he was right. Then he made the harder point. Sometimes you skip the AI on purpose, because a human already holds the context and handing it to the machine costs more than it saves. That's pragmatism, and it deserves a better answer than \"just use the tool.\"",[16,776,777],{},"I let the better frame arrive during the talk itself. These are residual barriers, the kind that only fall once you actually try. Calling them resistance flatters the person stuck behind one and hides the real shape of the problem.",[16,779,780],{},"He asked how I actually prompt, what an experienced user does in there. I told him the truth. I live-stream my brain. Write what I think when I think it, and follow the current. His next question was whether that means treating it like a person. It doesn't. Anthropomorphizing it and writing it off as a glorified autocomplete are both ways to lose. Go with the flow during a session, then step back on a schedule so it doesn't drift into AI psychosis.",[16,782,783],{},"Claude Code had been in the room the whole time, running as a live co-pilot on my screen. It spotted the writing angle before I named it. The deployment answer I'd forwarded to Nico verbatim was its. It named the pattern, activation energy, before Nico performed it. The tool we were talking about adopting was helping me talk him into adopting it, and he had no idea until I said so.",[16,785,786],{},"What you see posted is the finished build. The forty-five minutes of the brain refusing before it finally gives in is the part I wanted to write down. Tutorials hadn't moved him. He'd bookmarked the one from the car and still hadn't started. What moved him was a nudge from someone already running the tool, repeated until his brain stopped rejecting answers that were sitting in plain text. And the best nudge happened here by accident: a live conversation where the tool is already in the room, answering the next ten questions too. Once you're on it, the question shifts from \"can this platform do X\" to \"can I tell it to add X.\" Most of the time the answer is yes.",[16,788,789],{},"Forty-five minutes earlier he'd told me he didn't have time. Now he was saying there's no point fighting something that'll be part of how everyone works within five years. Then we put the laptops down and talked about Queens of the Stone Age. Once you've crossed the barrier, the whole thing stops being a big deal.",{"title":64,"searchDepth":65,"depth":65,"links":791},[],"People","people","2026-04-09T15:57:34.759Z","A long-standing client almost cried at a Claude Code tutorial, bookmarked it, and went back to his 400 Excel files. The forty-five minutes that followed taught me that AI adoption was never a knowledge problem.","c0ed8220-54f7-424e-ac26-3701113b99e7",{},"\u002Fposts\u002Fthe-gap-was-never-knowledge",{"title":729,"description":64},"the-gap-was-never-knowledge","posts\u002Fthe-gap-was-never-knowledge","yxr3i7io_M9OixEaII0ZdP2sxF5HZvjrKzbUa_hRLs8",{"id":804,"title":805,"body":806,"category_label":849,"category_slug":850,"date_created":851,"dek":852,"description":64,"directus_id":853,"extension":75,"is_promoted":76,"meta":854,"navigation":78,"path":855,"published_at":851,"seo":856,"slug":857,"status":82,"stem":858,"__hash__":859},"posts\u002Fposts\u002Fone-principle-beats-250-rules.md","One Principle Beats 250 Words of Rules",{"type":8,"value":807,"toc":844},[808,812,815,818,822,825,828,831,835,838,841],[11,809,811],{"id":810},"the-blocklist","The Blocklist",[16,813,814],{},"The client had a list. A long one. \"Ne jamais utiliser 'il est essentiel de'.\" \"Interdire 'dans le monde actuel'.\" \"Eviter 'il convient de noter que'.\" On and on. 250 words of \"don't say this.\"",[16,816,817],{},"I looked at it and felt the itch. This is whack-a-mole. You ban \"il est essentiel de,\" the LLM writes \"c'est fondamental de,\" same empty filler, different words. You add that to the list. Then it writes \"il est crucial de.\" You add that too. The list grows forever and never covers everything.",[11,819,821],{"id":820},"the-distillation","The Distillation",[16,823,824],{},"I asked Claude to challenge my instinct that this was inefficient. It agreed and went further: the entire 250-word list reduced to one principle.",[16,826,827],{},"\"Chaque phrase apporte une information nouvelle.\"",[16,829,830],{},"Eight words. Every sentence brings new information. That's it. That's the whole list. Every single banned phrase on that blocklist was banned because it adds no information. The principle catches all of them, plus every variant the LLM will ever generate.",[11,832,834],{"id":833},"the-broader-thing","The Broader Thing",[16,836,837],{},"The same pattern is everywhere, well past AI prompting. Code style guides with 400 rules vs. \"code should be obvious.\" Editorial guidelines with pages of don'ts vs. \"cut what the reader can skip.\" Team process documents with 50 bullet points vs. one principle people actually internalize.",[16,839,840],{},"Rules enumerate. Principles generate. A deny list will always be incomplete, while a positive directive covers cases you haven't seen yet.",[16,842,843],{},"~60 words instead of ~250. And it actually works.",{"title":64,"searchDepth":65,"depth":65,"links":845},[846,847,848],{"id":810,"depth":65,"text":811},{"id":820,"depth":65,"text":821},{"id":833,"depth":65,"text":834},"Knowledge Architecture","knowledge-architecture","2026-04-07T23:38:38.057Z","A client's prompt carried 250 words of banned phrases. Every one was banned for the same reason, so eight words replaced the whole list.","790e27e8-07bf-44f3-8af4-a506d937707f",{},"\u002Fposts\u002Fone-principle-beats-250-rules",{"title":805,"description":64},"one-principle-beats-250-rules","posts\u002Fone-principle-beats-250-rules","sCA_bUu-Cgzx9tiueCfpkxemLZyLfwD3tQoMWHqloPg",{"id":861,"title":862,"body":863,"category_label":480,"category_slug":481,"date_created":1259,"dek":1260,"description":64,"directus_id":1261,"extension":75,"is_promoted":76,"meta":1262,"navigation":78,"path":1263,"published_at":1259,"seo":1264,"slug":1265,"status":82,"stem":1266,"__hash__":1267},"posts\u002Fposts\u002Flocal-80b-beats-claude-coding.md","Why My Local 80B Model Beats Claude at Coding Tasks, and It's Not About the Model",{"type":8,"value":864,"toc":1248},[865,869,876,879,883,889,892,901,904,908,911,922,925,929,936,943,953,957,972,975,981,984,990,995,998,1001,1005,1012,1100,1106,1110,1145,1149,1192,1198,1202,1244],[11,866,868],{"id":867},"the-setup","The Setup",[16,870,871,872,875],{},"I run a dual RTX 3090 Ti homelab (HL1) serving Qwen3-Coder-Next 80B MoE (3B active params) via llama-server. The model is quantized to Q3_K_XL (33.79 GiB, 3.64 BPW) by Unsloth, running at 262K context with Q8 KV cache. Both GPUs stay under 57C at ~300W each. The stack is dead simple: llama.cpp build b8492, systemd service, K8s ingress with TLS, and ",[20,873,874],{},"ccq"," alias to point Claude Code at the local endpoint.",[16,877,878],{},"Everything worked. Inference was fast: 84 t\u002Fs generation, 2200 t\u002Fs prompt eval at 262K context. But something was very wrong with real-world agentic coding performance.",[11,880,882],{"id":881},"the-symptom","The Symptom",[16,884,885,886,888],{},"Every turn of a Claude Code (",[20,887,874],{},") session took ~15-20 seconds before the model even started generating. On a 31K token conversation, that's 20 seconds of pure waiting per tool call. An agentic task with 20 tool rounds = 7+ minutes of just prefill overhead.",[16,890,891],{},"The llama-server logs told the story:",[893,894,899],"pre",{"className":895,"code":897,"language":898},[896],"language-text","n_past = 35, slot.prompt.tokens.size() = 31327\nforcing full prompt re-processing due to lack of cache data\n(likely due to SWA or hybrid\u002Frecurrent memory)\n","text",[20,900,897],{"__ignoreMap":64},[16,902,903],{},"Every single turn: 35 tokens of prefix match. Full re-processing of 31K+ tokens from scratch. The checkpoints were being created, but immediately erased on the next request.",[11,905,907],{"id":906},"the-architecture-problem-or-so-i-thought","The Architecture Problem (Or So I Thought)",[16,909,910],{},"Qwen3-Coder-Next uses a hybrid architecture: 3 layers of Gated Delta Net (SSM\u002Frecurrent) alternating with 1 layer of Global Attention (3:1 ratio). Unlike pure Transformer models where KV cache handles prefix reuse natively, hybrid models need the recurrent state to be reconstructed from scratch when the token prefix diverges.",[16,912,913,914,917,918,921],{},"llama.cpp PR #20087 added ",[20,915,916],{},"--checkpoint-every-n-tokens N"," to snapshot the recurrent state during prefill, allowing restoration from the nearest checkpoint instead of reprocessing from position 0. I rebuilt to b8492, added ",[20,919,920],{},"--checkpoint-every-n-tokens 4096",", and validated with curl: checkpoint restored, 63% tokens saved.",[16,923,924],{},"But in real agentic use? Still full re-processing every turn.",[11,926,928],{"id":927},"the-wrong-hypothesis-parallel-slots","The Wrong Hypothesis: Parallel Slots",[16,930,931,932,935],{},"My first theory: with ",[20,933,934],{},"--parallel 4"," (default), the server assigns requests round-robin across 4 LRU slots. Each slot has its own checkpoints. A single-session agentic client bounces between slots, so the checkpoints from the previous turn are on a different slot.",[16,937,938,939,942],{},"Fix: ",[20,940,941],{},"--parallel 1",". Force everything onto one slot.",[16,944,945,946,949,950,952],{},"Result: no change. Still ",[20,947,948],{},"n_past = 34-35",". Still full re-processing. The checkpoints are there, but the server can't use them because the token prefix diverges at position 35. (Spoiler: ",[20,951,934],{}," turns out to matter later. Once the real problem is fixed, it cuts wall time nearly in half. But at this point in the investigation, it was a red herring.)",[11,954,956],{"id":955},"the-real-culprit-claude-codes-prompt-serialization","The Real Culprit: Claude Code's Prompt Serialization",[16,958,959,960,963,964,967,968,971],{},"The breakthrough came from testing with OpenCode (which uses the OpenAI ",[20,961,962],{},"\u002Fv1\u002Fchat\u002Fcompletions"," format) instead of Claude Code (which uses the Anthropic ",[20,965,966],{},"\u002Fv1\u002Fmessages"," format via ",[20,969,970],{},"ANTHROPIC_BASE_URL",").",[16,973,974],{},"Claude Code logs:",[893,976,979],{"className":977,"code":978,"language":898},[896],"n_past = 35, slot.prompt.tokens.size() = 39933\nforcing full prompt re-processing\nprompt eval time = 19511ms \u002F 39042 tokens\n",[20,980,978],{"__ignoreMap":64},[16,982,983],{},"OpenCode logs:",[893,985,988],{"className":986,"code":987,"language":898},[896],"selected slot by LCP similarity, sim_best = 0.995\nprompt eval time = 52ms \u002F 13 tokens\n",[20,989,987],{"__ignoreMap":64},[16,991,992,993,317],{},"52 milliseconds vs 19 seconds. Same model, same server, same ",[20,994,941],{},[16,996,997],{},"Claude Code re-serializes the entire prompt on every turn in a way that makes the token sequence diverge after ~35 tokens (roughly the end of the system prompt). The server sees a completely different token stream from position 36 onwards, so the KV cache, the recurrent state, and all checkpoints are useless.",[16,999,1000],{},"OpenCode maintains a stable prefix. The server finds 99.5%+ similarity, processes only the new tokens (~13-100 per turn), and the recurrent state checkpoints accumulate naturally (up to 30\u002F32 over a session).",[11,1002,1004],{"id":1003},"the-benchmark","The Benchmark",[16,1006,1007,1008,1011],{},"Same prompt, same task (Python interval scheduling library, 34 unit tests), all running in empty directories with ",[20,1009,1010],{},"--allowedTools"," to skip permission prompts:",[629,1013,1014,1033],{},[632,1015,1016],{},[635,1017,1018,1021,1024,1027,1030],{},[638,1019,1020],{},"Model",[638,1022,1023],{},"Time",[638,1025,1026],{},"Tests",[638,1028,1029],{},"Client",[638,1031,1032],{},"Config",[647,1034,1035,1052,1066,1083],{},[635,1036,1037,1040,1043,1046,1049],{},[652,1038,1039],{},"Opus (Anthropic API)",[652,1041,1042],{},"10:28",[652,1044,1045],{},"34\u002F34",[652,1047,1048],{},"Claude Code",[652,1050,1051],{},"n\u002Fa",[635,1053,1054,1057,1060,1062,1064],{},[652,1055,1056],{},"Sonnet (Anthropic API)",[652,1058,1059],{},"9:49",[652,1061,1045],{},[652,1063,1048],{},[652,1065,1051],{},[635,1067,1068,1071,1074,1076,1079],{},[652,1069,1070],{},"Qwen3-Coder-Next (local)",[652,1072,1073],{},"2:21",[652,1075,1045],{},[652,1077,1078],{},"OpenCode",[652,1080,1081],{},[20,1082,941],{},[635,1084,1085,1087,1092,1094,1096],{},[652,1086,1070],{},[652,1088,1089],{},[98,1090,1091],{},"1:02",[652,1093,1045],{},[652,1095,1078],{},[652,1097,1098],{},[20,1099,934],{},[16,1101,1102,1103,1105],{},"10x faster than Opus. Clean first pass, zero fix rounds. The model had previously failed this exact benchmark (circular imports, multiple fix iterations) when running through Claude Code. The config improvements since then helped, but the real unlock was the client switch. And once the client was fixed, restoring ",[20,1104,934],{}," gave an additional ~2x speedup. The parallelism that was useless with CC's broken prefix became a real advantage with OpenCode's stable one.",[11,1107,1109],{"id":1108},"what-i-learned","What I Learned",[165,1111,1112,1118,1124,1133],{},[119,1113,1114,1117],{},[98,1115,1116],{},"The client matters as much as the model."," Claude Code's prompt re-serialization is invisible to the user but catastrophic for incremental KV cache on hybrid SSM architectures. This is a CC-specific behavior. It doesn't affect pure Transformer models the same way because their KV cache is more forgiving of prefix mismatches.",[119,1119,1120,1123],{},[98,1121,1122],{},"Hybrid SSM models amplify cache misses."," With a pure Transformer, a prefix mismatch just means recomputing KV for the divergent suffix. With a hybrid model (Gated Delta Net + Attention), the recurrent state must be reconstructed from scratch, or from the nearest checkpoint if the prefix matches that far.",[119,1125,1126,1132],{},[98,1127,1128,1131],{},[20,1129,1130],{},"--checkpoint-every-n-tokens"," works, but only if the client cooperates."," The feature is sound. The curl tests proved it. But it's useless if the client rebuilds the prompt in a way that breaks prefix continuity.",[119,1134,1135,1141,1142,1144],{},[98,1136,1137,1140],{},[20,1138,1139],{},"--parallel N"," was a red herring, until it wasn't."," With CC's broken prefix, slot count doesn't matter: you can't reuse a recurrent state built from a different token sequence. But once the client cooperates (OpenCode), ",[20,1143,934],{}," cuts wall time from 2:21 to 1:02. The server can now overlap prefill and generation across slots because the cache actually works. The same config change that did nothing with CC gave a ~2x boost with OpenCode.",[11,1146,1148],{"id":1147},"the-workflow-now","The Workflow Now",[893,1150,1154],{"className":1151,"code":1152,"language":1153,"meta":64,"style":64},"language-bash shiki shiki-themes strip-chart","alias cc='claude'                              # Opus\u002FSonnet via Anthropic API\nalias ccq='OPENAI_API_KEY=... OPENAI_BASE_URL=https:\u002F\u002Fcode.llm.internal\u002Fv1 opencode run'\n","bash",[20,1155,1156,1180],{"__ignoreMap":64},[1157,1158,1161,1165,1169,1172,1176],"span",{"class":1159,"line":1160},"line",1,[1157,1162,1164],{"class":1163},"sTLRP","alias",[1157,1166,1168],{"class":1167},"sAP0c"," cc",[1157,1170,1171],{"class":1163},"=",[1157,1173,1175],{"class":1174},"sFa7Q","'claude'",[1157,1177,1179],{"class":1178},"sql22","                              # Opus\u002FSonnet via Anthropic API\n",[1157,1181,1182,1184,1187,1189],{"class":1159,"line":65},[1157,1183,1164],{"class":1163},[1157,1185,1186],{"class":1167}," ccq",[1157,1188,1171],{"class":1163},[1157,1190,1191],{"class":1174},"'OPENAI_API_KEY=... OPENAI_BASE_URL=https:\u002F\u002Fcode.llm.internal\u002Fv1 opencode run'\n",[16,1193,1194,1195,1197],{},"Design with Opus\u002FSonnet in Claude Code. Write the code with ",[20,1196,874],{}," (OpenCode + Qwen local). Review with Opus\u002FSonnet. The local model handles the heavy lifting at 10x the speed, zero API cost, and full 262K context. Claude Code stays for Anthropic models only.",[11,1199,1201],{"id":1200},"relevant-llamacpp-issues","Relevant llama.cpp Issues",[116,1203,1204,1214,1222,1234],{},[119,1205,1206,1213],{},[1207,1208,1212],"a",{"href":1209,"rel":1210},"https:\u002F\u002Fgithub.com\u002Fggml-org\u002Fllama.cpp\u002Fissues\u002F18497",[1211],"nofollow","#18497",": cache-reuse not effective for qwen3-next",[119,1215,1216,1221],{},[1207,1217,1220],{"href":1218,"rel":1219},"https:\u002F\u002Fgithub.com\u002Fggml-org\u002Fllama.cpp\u002Fissues\u002F20225",[1211],"#20225",": full prompt re-processing on every conversation turn",[119,1223,1224,1229,1230,1233],{},[1207,1225,1228],{"href":1226,"rel":1227},"https:\u002F\u002Fgithub.com\u002Fggml-org\u002Fllama.cpp\u002Fissues\u002F19794",[1211],"#19794",": ",[20,1231,1232],{},"--swa-full"," ineffective for Qwen3-Coder-Next",[119,1235,1236,1229,1241,1243],{},[1207,1237,1240],{"href":1238,"rel":1239},"https:\u002F\u002Fgithub.com\u002Fggml-org\u002Fllama.cpp\u002Fpull\u002F20087",[1211],"PR #20087",[20,1242,1130],{}," (the fix that works, if the client cooperates)",[1245,1246,1247],"style",{},"html pre.shiki code .sTLRP, html code.shiki .sTLRP{--shiki-default:var(--code-token-keyword)}html pre.shiki code .sAP0c, html code.shiki .sAP0c{--shiki-default:var(--code-foreground)}html pre.shiki code .sFa7Q, html code.shiki .sFa7Q{--shiki-default:var(--code-token-string-expression)}html pre.shiki code .sql22, html code.shiki .sql22{--shiki-default:var(--code-token-comment)}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":64,"searchDepth":65,"depth":65,"links":1249},[1250,1251,1252,1253,1254,1255,1256,1257,1258],{"id":867,"depth":65,"text":868},{"id":881,"depth":65,"text":882},{"id":906,"depth":65,"text":907},{"id":927,"depth":65,"text":928},{"id":955,"depth":65,"text":956},{"id":1003,"depth":65,"text":1004},{"id":1108,"depth":65,"text":1109},{"id":1147,"depth":65,"text":1148},{"id":1200,"depth":65,"text":1201},"2026-03-23T22:50:08.331Z","A local 80B on two 3090 Tis finished the benchmark in 1:02 against Opus's 10:28, and the only thing I changed was the client. Claude Code re-serializes the whole prompt every turn, which kills prefix reuse on hybrid SSM models and costs 20 seconds of re-prefill per tool call.","0c8a57ac-5681-44d2-9d6d-12ec9c4c1861",{},"\u002Fposts\u002Flocal-80b-beats-claude-coding",{"title":862,"description":64},"local-80b-beats-claude-coding","posts\u002Flocal-80b-beats-claude-coding","NCe5kWmDjzq5zjfiQ93f22a70YGHU183eszXmFid8fE",{"id":1269,"title":1270,"body":1271,"category_label":480,"category_slug":481,"date_created":1334,"dek":1335,"description":64,"directus_id":1336,"extension":75,"is_promoted":76,"meta":1337,"navigation":78,"path":1338,"published_at":1334,"seo":1339,"slug":1340,"status":82,"stem":1341,"__hash__":1342},"posts\u002Fposts\u002Fwhen-84-percent-token-reduction-means-zero-accuracy.md","When 84% Token Reduction Means Zero Accuracy",{"type":8,"value":1272,"toc":1328},[1273,1275,1278,1281,1285,1288,1291,1294,1298,1309,1312,1316,1319,1322,1325],[11,1274,868],{"id":867},[16,1276,1277],{},"I had been evangelizing semantic code search for weeks. VectorCode promised to cut through large codebases by understanding meaning, not just matching strings. So I did what I should have done from the start: I ran a real benchmark.",[16,1279,1280],{},"The task was concrete: debug a payment processing bottleneck in a Laravel app. The files that had to be found were PaymentHubController at the entry point, GatewayPaymentHubService where the bottleneck lived, GatewayPayment with the N+1 query, and PaymentRepository underneath it. A realistic debugging scenario, not some toy example.",[11,1282,1284],{"id":1283},"the-numbers-that-stung","The Numbers That Stung",[16,1286,1287],{},"Vanilla Claude Code: 91,457 tokens, 38 tool calls, 142 seconds. Found all 4 critical files. 100% accuracy.",[16,1289,1290],{},"VectorCode: roughly 15,000 tokens, 6 queries, 8 seconds. Found zero critical files. 0% accuracy.",[16,1292,1293],{},"I stared at that for a while. An 84% token reduction sounds incredible until you realize it produced 100% false positives. You save nothing when the answer is wrong. It is like bragging about fuel efficiency on a car that drives to the wrong city.",[11,1295,1297],{"id":1296},"why-it-failed","Why It Failed",[16,1299,1300,1301,1304,1305,1308],{},"The failure modes were instructive. Semantic embeddings are great at matching documentation and test files, things written in natural language that describe what code does. But terse code? Variable names like ",[20,1302,1303],{},"$gatewayPayment"," and method signatures like ",[20,1306,1307],{},"processHubPayment()","? The embeddings had no idea what to do with those. VectorCode matched conceptually adjacent files (docs about payments, test helpers) instead of the code that mattered.",[16,1310,1311],{},"Meanwhile, vanilla CC did what good debugging actually looks like. It followed the framework's structure: routes to controllers to services to repositories. Pattern-based discovery. Progressive refinement. It knew Laravel, so it knew where to look. No semantic magic needed, just methodical grep-and-read cycles.",[11,1313,1315],{"id":1314},"what-i-actually-learned","What I Actually Learned",[16,1317,1318],{},"My first instinct was to throw VectorCode out entirely. But that felt reactionary. The tool is fine. I was aiming it at the wrong job. When I asked it conceptual questions like \"how does payment processing work in this codebase?\" it returned useful orientation results. It is a discovery tool, and I had been using it as a precision one.",[16,1320,1321],{},"The hybrid approach is the real answer. VectorCode for the \"I just joined this project, where do I even start?\" phase. Vanilla tools for \"there is an N+1 query somewhere in the payment flow and I need to find it now.\"",[16,1323,1324],{},"Token efficiency is worth counting only when the answer stays right. An 84% reduction that produces garbage is waste with better optics.",[16,1326,1327],{},"I am glad I ran the benchmark before building my entire workflow around it. The numbers do not care about my enthusiasm.",{"title":64,"searchDepth":65,"depth":65,"links":1329},[1330,1331,1332,1333],{"id":867,"depth":65,"text":868},{"id":1283,"depth":65,"text":1284},{"id":1296,"depth":65,"text":1297},{"id":1314,"depth":65,"text":1315},"2026-03-02T16:15:40.904Z","Semantic code search cut my token spend by 84% on a real Laravel debugging task and found zero of the four files that mattered. I had been evangelizing the tool for weeks before I finally benchmarked it.","16d46683-a587-4d4f-b62a-b352b3698dce",{},"\u002Fposts\u002Fwhen-84-percent-token-reduction-means-zero-accuracy",{"title":1270,"description":64},"when-84-percent-token-reduction-means-zero-accuracy","posts\u002Fwhen-84-percent-token-reduction-means-zero-accuracy","z_VtyoPypiHuUCLBGrcZl-sI1YJgX7WRN-z9dTeR-2U",{"id":1344,"title":1345,"body":1346,"category_label":332,"category_slug":333,"date_created":1457,"dek":1458,"description":64,"directus_id":1459,"extension":75,"is_promoted":76,"meta":1460,"navigation":78,"path":1461,"published_at":1457,"seo":1462,"slug":1463,"status":82,"stem":1464,"__hash__":1465},"posts\u002Fposts\u002Fbuilding-my-own-content-pipeline.md","I Built a Content Pipeline Because I Was Tired of Copy-Pasting",{"type":8,"value":1347,"toc":1451},[1348,1352,1355,1358,1361,1365,1371,1386,1393,1404,1407,1411,1418,1421,1426,1429,1434,1438,1445,1448],[11,1349,1351],{"id":1350},"the-problem","The problem",[16,1353,1354],{},"I write things. Blog posts. LinkedIn takes. X threads, Dev.to write-ups, Bluesky one-liners. Every publish was the same ritual. Write in one place, copy-paste to three others, fiddle the tone, lose track of what went where.",[16,1356,1357],{},"Not hard work. Death-by-a-thousand-cuts work. The kind that stays under the radar until you realize you've been spending an hour after every post on copy-paste hygiene.",[16,1359,1360],{},"So I built the pipeline I wished I had.",[11,1362,1364],{"id":1363},"what-i-actually-built","What I actually built",[16,1366,1367,1368,317],{},"Local-first. Docker Compose. Directus as the headless CMS, Postgres underneath, n8n for workflow orchestration. Three containers, one ",[20,1369,1370],{},"docker-compose up",[16,1372,1373,1374,1377,1378,1381,1382,1385],{},"The capture surface lives in Claude Code. A skill called ",[20,1375,1376],{},"capture-thought"," watches for moments mid-session (debugging, refactoring, whatever) when I drop a line like \"save this as a writing idea, btw.\" The skill writes a raw markdown file to ",[20,1379,1380],{},"~\u002FNextcloud\u002FSync\u002Fwriting\u002Fraw\u002F"," and syncs it to Directus with status ",[20,1383,1384],{},"idea",". The thought is preserved before it evaporates. Cost to me: half a sentence.",[16,1387,1388,1389,1392],{},"Then ",[20,1390,1391],{},"elaborate-post",", a second skill that takes the raw idea and develops it into a draft. Tags. Excerpt. Cards. Body cleaned up.",[16,1394,1395,1396,1399,1400,1403],{},"The interesting part is what happens after. n8n watches for posts ready to syndicate and routes them to platforms based on tags. ",[20,1397,1398],{},"tech"," goes to the blog, Dev.to, and X. ",[20,1401,1402],{},"freelance"," hits LinkedIn. An LLM generates platform-specific variants, same core idea, different voice for each audience. It pushes to LinkedIn (3000 char), X (280), Dev.to, the blog, Malt (2000) and Bluesky (300).",[16,1405,1406],{},"The routing matrix is the design decision I'm proudest of. Tags route to platforms via a relevance score (high \u002F medium \u002F low \u002F excluded). I don't pick platforms per-post. I tag, and the matrix decides. Per-post selection doesn't scale. Once you have 50 posts, every \"where should this go?\" decision becomes friction. Tag-based routing scales linearly with new platforms, not with new posts.",[11,1408,1410],{"id":1409},"why-not-notion-or-buffer","Why not Notion or Buffer",[16,1412,1413,1414,1417],{},"Because I wanted the content to live where I control it. Local Postgres, local files as backup, everything versioned. The whole stack portable via ",[20,1415,1416],{},"pg_dump"," and a Directus schema snapshot.",[16,1419,1420],{},"There's an old principle I keep coming back to:",[349,1422,1423],{},[16,1424,1425],{},"Every post on someone else's platform is renting space. Every post on your own domain is equity.",[16,1427,1428],{},"Same logic for the pipeline that produces those posts. If Buffer changes their pricing, breaks their LinkedIn integration, or just disappears, my pipeline doesn't notice.",[16,1430,1431,1432,317],{},"The constraint that drove this is 2AM. I get ideas while debugging production, and I need to grab them in three words before they evaporate. Buffer doesn't speak ",[20,1433,1376],{},[11,1435,1437],{"id":1436},"the-meta-thing","The meta thing",[16,1439,1440,1441,1444],{},"I'm capturing this thought ",[25,1442,1443],{},"using the very pipeline I'm writing about",", which is either poetic or deeply nerdy. Probably both.",[16,1446,1447],{},"That recursion isn't an accident. The pipeline is opinionated about one thing: capture must be cheap enough that thinking and writing happen in the same gesture. Once you've built that, every thought you have about the pipeline becomes pipeline content. The system feeds itself.",[16,1449,1450],{},"That's the part Buffer can't sell you. You have to build it.",{"title":64,"searchDepth":65,"depth":65,"links":1452},[1453,1454,1455,1456],{"id":1350,"depth":65,"text":1351},{"id":1363,"depth":65,"text":1364},{"id":1409,"depth":65,"text":1410},{"id":1436,"depth":65,"text":1437},"2026-03-02T16:05:05.672Z","I was burning an hour after every post on copy-paste hygiene. So I built the pipeline I wished I had. Directus, n8n, Claude Code, all local-first.","04649e21-8317-4159-9c8d-b612bcd018fb",{},"\u002Fposts\u002Fbuilding-my-own-content-pipeline",{"title":1345,"description":64},"building-my-own-content-pipeline","posts\u002Fbuilding-my-own-content-pipeline","GOZxOoo8pBaQskpKcryttGyGwVnm5KEbPMVD8lA8kpw",[1467,1475,1482,1488,1494,1501],{"id":1468,"description":1469,"extension":1470,"label":70,"meta":1471,"order":1472,"post_count":1160,"slug":71,"stem":1473,"__hash__":1474},"categories\u002Fcategories\u002Fcraft.json","Close-read posts on the daily work of shipping software.","json",{},0,"categories\u002Fcraft","bAfaerFLn5gKJyzXQLTEy95inz6saFE03vKNGDNWwNw",{"id":1476,"description":1477,"extension":1470,"label":480,"meta":1478,"order":1160,"post_count":1479,"slug":481,"stem":1480,"__hash__":1481},"categories\u002Fcategories\u002Fskeptics-toolbox.json","The cases against default narratives; what doesn't hold up under scrutiny.",{},3,"categories\u002Fskeptics-toolbox","hPOh22rNWxW_dewYrYcLgnrEDIv_sY17XJAlLjRxTe4",{"id":1483,"description":1484,"extension":1470,"label":332,"meta":1485,"order":65,"post_count":65,"slug":333,"stem":1486,"__hash__":1487},"categories\u002Fcategories\u002Fbuild-log.json","Field notes from building specific systems, in progress.",{},"categories\u002Fbuild-log","_YPWw94FFI3NAi5oP4e4Z_N0AcFBLoywskvd-MT0les",{"id":1489,"description":1490,"extension":1470,"label":716,"meta":1491,"order":1479,"post_count":1160,"slug":717,"stem":1492,"__hash__":1493},"categories\u002Fcategories\u002Fml-journal.json","Learning ML in public. Failures, diagnoses, partial wins.",{},"categories\u002Fml-journal","0PP-FTOq2_F3lMsfbjdhi3q9TqLm3ajKZCqt9kXAXCM",{"id":1495,"description":1496,"extension":1470,"label":849,"meta":1497,"order":1498,"post_count":1160,"slug":850,"stem":1499,"__hash__":1500},"categories\u002Fcategories\u002Fknowledge-architecture.json","How knowledge is structured, captured, retrieved, transmitted.",{},4,"categories\u002Fknowledge-architecture","acvknIIMKZMnFb9-VBtiSIDksRlzGbGMQUpyFX-SMns",{"id":1502,"description":1503,"extension":1470,"label":792,"meta":1504,"order":1505,"post_count":1160,"slug":793,"stem":1506,"__hash__":1507},"categories\u002Fcategories\u002Fpeople.json","Stories about humans in the work — collaborators, clients, collaborators in absentia.",{},5,"categories\u002Fpeople","9rpzEOrRX1WY5EmvqmKGOyGuAwvs2IXaPT9IfCoJfn4",1786607568636]