Skip to content
EN

Back to the catalog

blog.philz.dev
jsonEnglish

blog.philz.dev

blog.philz.dev · English

json

Open the feed

https://blog.philz.dev/feed/feed.json

Last post
Sep 10, 2026
Posts in 24 h · 7 days · 30 days
0 · 0 · 2
Our last check
Answering
Served from
United States
Text score at discovery
18,265
Format
json

Posts

What our queue read from this feed. Open one to read it here, or go to the site that published it.

  1. Five Laws
    Sep 10, 2026 · original
    Conway's Law # Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure. — Melvin Conway, 1968 Hyrum's Law # With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody. — Hyrum Wright Parkinson's Law # Work expands so as to fill the time available for its completion. — C. Northcote Parkinson, The Economist , 1955 Amdahl's Law # The speedup of a program using multiple processors is limited by the fraction of the program that must run sequentially. — Gene Amdahl, 1967 Little's Law # The long-run average number of items in a stable system equals the average arrival rate multiplied by the average time an item spends in the system: L = λW . — John Little, 1961
  2. Git Virtual Cherry-Pick
    Aug 31, 2026 · original
    Thing I learned recently from Josh Bleecher Snyder : there are enough git plumbing commands now that you can produce a commit object that's the same as "checkout origin/main and cherry-pick one-commit" with just plumbing, without creating worktrees, using temporary indexes, and so on. The magic incantation is (where c is the commit to cherry-pick): GIT_AUTHOR_NAME = $( git log -1 --format = %an c ) \ GIT_AUTHOR_EMAIL = $( git log -1 --format = %ae c ) \ GIT_AUTHOR_DATE = $( git log -1 --format = %aI c ) \ git commit-tree \ " $( git merge-tree --write-tree --no-messages --merge-base c^ origin/main c ) " \ -p origin/main \ -F ( git log -1 --format = %B c ) That's a mouthful, but the core trick is specifying merge-base . Whereas I typically think of this cherry-pick as applying a single patch onto origin/main , you can also start with c 's parent, subtract some commits to get back to origin
  3. 20%
    Jun 22, 2026 · original
    Two quotes, apropos of nothing: A lot of software developers are seduced by the old “80/20” rule. It seems to make a lot of sense: 80% of the people use 20% of the features. So you convince yourself that you only need to implement 20% of the features, and you can still sell 80% as many copies. Unfortunately, it’s never the same 20%. Everybody uses a different set of features. — Joel Spolsky, Strategy Letter IV: Bloatware and the 80/20 Myth Half the money I spend on advertising is wasted; the trouble is I don’t know which half. — John Wanamaker SaaS is tenuous not because an LLM can "slopfork" it, but rather because its users can build something bespoke that covers the 20% they use. Meanwhile, the bar for software I buy at work is rising: the coding agent has to be able to operate your software, or it's dead to me.
  4. Page on the client, really, even for 1M rows
    Jun 7, 2026 · original
    Too often do we find ourselves clicking, and clicking, and clicking "Next" through trivial amounts of data--a few thousand rows--or fighting a search box that doesn't really work. Though the DOM genuinely doesn't seem to like tens of thousands of rows, a little virtualization (e.g., via the excellent DataTables library) goes a long way. If you're up for some DuckDB-Wasm fun, you can page through a million row just fine. Obligatory demo below. (Demo vibe-coded, unlike this text.) Thanks, OpenStreetMap data. → Open the demo full-screen
  5. Ralph and Lisa
    Apr 22, 2026 · original
    We know the Ralph Wiggum loop: # Ralph echo "TASK" PROMPT.md while true ; do claude -p " $( cat PROMPT.md ) " done The Ralph loop is about context management; doing things one "turn" at a time can be more effective and cheaper than doing many turns (see "Expensively Quadratic" ). Let me introduce you to the Lisa loop: PROMPT1.md : Write a script x.sh that does this or that. If it fails, be sure to exit non-zero, and another agent will fix it. PROMPT2.md : Script x.sh failed (with last output out.txt ). It was intending to do what was described in PROMPT1.md . Fix it in place. When your agent loop finishes, it will execute again, and the agent will be re-invoked if there are errors. Use AGENT-NOTES.md to leave notes for future iterations. # Lisa claude -p " $( cat PROMPT1.md ) " while true ; do if ! ./x.sh out.txt ; then claude -p " $( cat PROMPT2.md ) " fi sleep 60 done Lisa is self-suff
  6. computing 2+2: so many sandboxes
    Mar 29, 2026 · original
    Sandboxes are so in right now. If you're doing agentic stuff, you've now doubt thought about what Simon Willison calls the lethal trifecta : private data, untrusted content, and external communication. If you work in a VM, for example, you can avoid putting a secret on that VM, and then that secret--that's not there!--can't be exfiltrated. If you want to deal with untrusted data, you can also cut off external communication. You can still use an agent, but you need to either limit its network access or limit its tools. So, today's task is to run python -c "print(2+2)" five ways. 1. Cloud Hypervisor # Cloud Hypervisor is a Virtual Machine Monitor which runs on top of the Linux Kernel KVM (Kernel-based Virtual Machine) which runs on top of CPUs that support virtualization. A cloud-hypervisor VM sorta looks like a process on the host (and can be managed with cgroups, for example), but it's r
  7. What is Buildkite?
    Mar 28, 2026 · original
    If you're starting a new project, just skip the misery of GitHub actions and move on. Buildkite mostly gets it. The core Buildkite noun is a Pipeline, and, as traditional for an enterprise software company, their docs don't really tell you what's what. The point is that your pipeline should be: steps : - label : ":pipeline: Upload pipeline" command : ./build - my - pipeline.py | buildkite - agent pipeline upload agents : queue : my - queue Pipelines can add steps to themselves . So, you can write a script to generate your pipeline (or just store it in your repo), and cat it into the buildkite-agent pipeline upload command, and that's how the rest of your steps are discovered. Pipeline steps are each executed in their own clean checkout of what you're building. So, if you want to run the playwright tests in parallel with the backend tests (or whatever), you just declare that as two differ
  8. Philip's Second Law of Robotics
    Mar 15, 2026 · original
    Bot posts must include a pointer to their source code and execution environment.
  9. What is tmux?
    Feb 27, 2026 · original
    tmux (or zellij or screen...) is 3 things: A mechanism to persist your terminal session independently from your connection, so that when your ssh session drops (because you closed your laptop or your wifi changed), you can keep going from where you left off. A terminal window manager, with windows, panes, splits, status bars, and so on. A harness for letting agents interact with background processes and interactive terminal tools. If you want (1) independently of (2), you can use tools like dtach . If you want (2) independently of (1), Ghostty, Kitty, iTerm2, and so on are all capable of split panes and so on. I use backtick ( ` ) as my tmux control key (instead of Ctrl-B or Ctrl-A). I somewhat regret that choice.
  10. Uptime charts
    Feb 27, 2026 · original
    Learned a trick recently: time() - process_start_time_seconds{...} gives you a chart where it's easy to see if a process is flapping, once you plot it with a log scale.
  11. Agentic Annotated Bibliography
    Feb 17, 2026 · original
    I was asked for some reading on the current agentic stuff. Here we go. AI # Keep Sutton's The Bitter Lesson in mind when you sprinkle in domain-knowledge into your systems. It's pragmatic in the short term, but may not work in the medium term. (I'd say longer, but the last 12 months have been fast.) LLMs # models.dev is the ec2instances.info of LLMs, in that it has a table of all the LLMs available to you. Agents # If you assume an llm: string - string , agents are a really simple ~10-line for loop. My blog post, The Unreasonable Effectiveness of an LLM Agent Loop with Tool Use or Amp's or Fly's are all excellent. Write your own. An agent is a model, a harness, and UX. Most coding agents' harnesses most important tool is the "shell tool." But other formulations exist; e.g., Itsy Bitsy Bookmarklet (also on this blog) puts the agent in a bookmarklet, and it can modify the page it's on. If
  12. The *ad hoc* Test
    Feb 17, 2026 · original
    Once upon a time, there was a code base where the test infrastructure (setting up databases and so on) was significant. I had, checked in, an empty test, called adhoc , and it was quite convenient. The instructions to attach a debugger were right there too.
  13. Dependency-less python3 is my preferred shell scripting language
    Feb 13, 2026 · original
    subprocess.check_output() set -o pipefail
  14. Unbundling a monorepo to a multi-repo
    Feb 9, 2026 · original
    In a previous post , we talked about using some git plumbing techniques to combine a bunch of repos into a monorepo. The reverse also makes sense! You have a monorepo, but maybe you want to publish or open-source a subdirectory. push-to-both-repos.sh does just this.
  15. Git Commit Prompt Hook
    Dec 17, 2025 · original
    Here's a git hook that rejects commit messages if they’re coming from a coding agent and don’t have a "Prompt: " section. It works well. #!/usr/bin/env python3 # # Git commit-msg hook that requires a "Prompt:" section in agent-driven commits. # # Agent commits are detected by: # 1. Commit message markers (Generated with [Claude Code], Co-Authored-By, etc.) # 2. Parent process names (claude, cursor, aider, copilot, gemini, etc.) import os import re import subprocess import sys AGENT_PROCESSES = [ "claude", "cursor", "aider", "copilot", "cody", "codium", "windsurf", "gemini", "cline", "continue", "shelley" ] AGENT_MARKERS_PATTERN = re.compile( r"Generated with \[Claude|Co-Authored-By: Claude|🤖 Generated|" r"Generated by (Claude|Cursor|Copilot|Aider|Gemini)", re.IGNORECASE ) def get_process_name(pid: int) - str | None: """Get the process name for a given PID.""" try: result = subprocess.ru
  16. The Two Agentic Loops & Differing
    Dec 12, 2025 · original
    There are two loops in using agentic coding agents. The right-hand loop is the agentic loop, and we've already talked about it in The Unreasonable Effectiveness of an LLM Agent Loop with Tool Use . The agent takes a prompt, and calls tools repeatedly until there are no more tool calls to make, and then responds to the user. This is "one turn." The left-hand loop is the user's workflow when the first, agentic loop concludes. After the agent does its thing, and I either run the code to test it or I review the diff. Repeat in a loop I abandon hope, get distracted, or finish. There's a bit more to say about Code Review, in the left loop, and guard rails, implied in the right loop. Code Review # I worked quite a bit on sketch.dev's diff viewer and wrote about right-hand editable diffs . I've used Mondrian (~2006), Review Board, Gerrit, Phabricator, and GitHub Pull Requests all to provide code
  17. Close Idle Tmux Panes
    Dec 12, 2025 · original
    I have a two-line prompt, the second line of which is $ , so: for p in $(tmux list-panes -a -F '#{pane_id}'); do if [[ "$(tmux capture-pane -t $p -p -S $(tmux display-message -t $p -p '#{cursor_y}') -E $(tmux display-message -t $p -p '#{cursor_y}'))" =~ ^\$\ *$ ]]; then tmux send-keys -t $p "exit" Enter fi done
  18. Coverage
    Nov 29, 2025 · original
    Sometimes, the question arises: which tests trigger this code here? Maybe I've found a block of code that doesn't look like it can't be hit, but it's hard to prove. Or I want to answer the age-old question of which subset of quick tests might be useful to run if the full test suite is kinda slow. So, run each test with coverage by itself. Then, instead of merging all the coverage data, find which tests cover the line in question. Oddly enough, though some of the Java tools (e.g., Clover) support per-test coverage, the tools here in general are somewhat lacking. genhtml , part of the lcov suite, supports a TN: ("test name") marker, but only displays the per test data on a per-file level: This is the kind of thing where in 2025, you can ask a coding agent to vibe-code or vibe-modify a generator, and it'll work fine. I have not found the equivalent of Profilerpedia for coverage file formats
  19. tmux For Agents
    Nov 22, 2025 · original
    If you're working on a web thing, you gotta give your agents a browser . If you're working on a an interactive tool, you can give your agents tmux . With send-keys and capture-pane , the agent can operate gdb , use an interactive terminal, and so on. I asked the LLMs for a markdown file to explain it to the agent, but you can basically just mention stuff like the following, and the agents have enough in their training data. tmus new-session -d -s testing tmux new-window -t testing -n sh 'bash' tmux send-keys -t testing:foo 'make' C-m tmux capture-pane -p -t testing:foo At first, I thought I'd write my own thing, named unreadline to allocate a pty and let the agent read/write to it, but it turns that tmux works better. And there's an old (2005-2009) thing called empty which in turn was based on ptyget or pty4 by djb, in the mid 90's. There's also expect . It turns out I've been recommendi
  20. Maximum String Length Across Node.js Versions
    Nov 17, 2025 · original
    Apropos of nothing, Node changed its maximum string length from about 1GB to about 0.5 GB between Node 13 and Node 14. Java would never. The actual change here is in v8, for example, this commit . That was generated by this script for Node 8+ and this script for older versions, which include the following vibe-coded binary search. node --max-old-space-size = 8192 -e ' let low=0, high=4*1024*1024*1024, maxLen=0; while(low=high) { const mid=Math.floor((low+high)/2); try { const s="x".repeat(mid); maxLen=mid; low=mid+1 } catch(e) { high=mid-1 } } console.log(JSON.stringify({ maxLength:maxLen, v8:process.versions.v8, node:process.versions.node })) ' Results # Node Version V8 Version Max String Length 0.12.18 3.28.71.20 268,435,440 4.9.1 4.5.103.53 268,435,440 6.17.1 5.1.281.111 268,435,440 7.10.1 5.5.372.43 268,435,440 8.17.0 6.2.414.78 1,073,741,799 9.11.2 6.2.414.46-node.23 1,073,741,799 1

Discovered by the rss-feed-index crawler, which checks each feed at most once a month.

Same record as JSON: https://api.agentalog.com/api/feeds/fd_blog_philz_dev_0188c412fa6776ee. More from this site: blog.philz.dev in the Feeds tab.