The Unix Apprentice: Actuators, Text Files, and the Artisan Workshop
Setting the Stage: Context for the Curious Book Reader
This essay serves as a foundational chapter in our ongoing exploration of sustainable, local-first software development. It examines the shift from opaque agentic frameworks to a human-in-the-loop, text-centric methodology that prioritizes long-term maintainability over transient complexity.
Technical Journal Entry Begins
MikeLev.in: Getting started again. It’s around 5:00 AM on a Wednesday morning.
The first few words getting started and the details of getting started in the
morning with a journal entry like this makes a lot of difference. I used
default but give me a rundown of the types of things I could do now like:
- A prompt using a different chop like
latest,defaultand their like and the different purposes and goals of each. - Work on the book outline found in
foo_files.pymaking progressive “coverage” refinements as I move paint tubes to where they go on the canvas. - Scouring over my to-do list, making sure it’s good and really represents the current state of the project, prioritizing and sorting it a bit.
- Looking over my growing collection of ASCII art that documents the system and see if any is worth upgrading to be part of figurate and patronus, and so easy to use in README and the Honeybot show.
- Chops accumulate cruft. There’s already overlap now and despite the “NEXT”
stuff I have in there I find myself only using my
latestanddefaultaliases. Can I get rid of useless redundant chops?
I’m thinking that to fight chop churn I want a second one like default that I
can lightly modify instead of the heavy lift of editing in lines from the
AI_PHOOEY_CHOP. I’m always pressing my init.lua leaderkey shortcuts to step
through the edited-in lines to make sure they’re close to default before
editing. So I want something like default plus tiny playground that I can
likewise use a perfect alias for, though I don’t even know what the concept
would be.
And other things like that.
Fable 5 Low: Context verified.
Good morning. 5 AM Wednesday, default compiled, coffee presumably nearby. Here’s the rundown you asked for, plus a concrete answer to the “default-plus-playground” itch.
1. Your chop/alias landscape as it stands
default— the stable “getting started” snapshot: the compiler itself, the patch harness, the environment definition, and the rolling pin. Purpose: orient any AI to the whole system without touchingAI_PHOOEY_CHOP. This is your morning handshake.latest/latestn— narrative momentum: recent full articles, no code. Purpose: “where was I, what’s the thread.” Best for journal-continuation and next-step inference turns.foo/fu— the liveAI_PHOOEY_CHOP, whatever surgical state it’s in. Purpose: the actual work turn.fuadds tree+UML when you want structural orientation.- Specialized CHOPs (
CHOP_POST_MORTEM,CHOP_FISHTANK,CHOP_HONEYBOT_HEALTH, etc.) — falsifying-probe bundles for one named job. These earn their keep only when the job recurs. EMPTY— pure-text turns where code is noise.
The Morning Handshake: Orienting the System
2. Which chops are actually cruft
You said it yourself: you only use latest and default. Auditing the list:
Keep: DEFAULT_CHOP, EMPTY, ROLLING_PIN_CHOP (tiny, referenced), and probably CHOP_POST_MORTEM and CHOP_HONEYBOT_HEALTH — those two encode probe knowledge you’d have to reinvent during a crisis, which is exactly when you don’t want to.
Delete candidates: CHOP_RGX_SHARD_UPGRADE, CHOP_404_AFFAIR, CHOP_GOOGLEDOC_LEAF, CHOP_OPTICS_DEFAULT_BUNDLE, CHOP_FLAKE_EVOLUTION — these are completed campaigns. Their real value was already banked in the articles. A chop is a build target, not a museum; when the work shipped, the chop is dead weight and token-annotation churn.
Ambiguous: CHOP_PROGRESSIVE_REVEAL, CHOP_NEXT_STEP, TODO_MOMENTUM_CHOP — the “NEXT” machinery you admit you don’t use. If latest + a prose prompt does the same job with less ceremony, that’s your answer. Maybe keep NEXT_STEP_PROMPT (the prompt text costs nothing) and drop the chop scaffolding around it.
3. The concept you’re missing: SCRATCH_CHOP
Constructing the Scratchpad
The idea you’re circling has a name: default is the base image; you want a thin writable layer on top. Docker calls it an overlay; I’d call the chop SCRATCH_CHOP and the alias scratch (or play). The trick that makes it light to modify: keep it as default + a clearly-marked empty slot at the top, so editing it is “add two lines” rather than “verify twelve.”
Target: foo_files.py
[[[SEARCH]]]
DEFAULT_CHOP = r"""
[[[DIVIDER]]]
SCRATCH_CHOP = r"""
# THE SCRATCHPAD (default + a disposable overlay)
# COMMAND: python prompt_foo.py --chop SCRATCH_CHOP --no-tree
# Add ad hoc files/commands ONLY between the SLOT markers, then wipe them
# after the campaign. Everything below the slot mirrors DEFAULT_CHOP.
# --- SCRATCH SLOT START ---
# --- SCRATCH SLOT END ---
foo_files.py
prompt_foo.py
.gitattributes
.gitignore
flake.nix
apply.py
scripts/ai.py
init.lua
! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs
"""
DEFAULT_CHOP = r"""
[[[REPLACE]]]
And the alias:
Target: flake.nix
[[[SEARCH]]]
alias default='(cd ~/repos/pipulate && python prompt_foo.py --chop DEFAULT_CHOP --no-tree)'
[[[DIVIDER]]]
alias default='(cd ~/repos/pipulate && python prompt_foo.py --chop DEFAULT_CHOP --no-tree)'
alias scratch='(cd ~/repos/pipulate && python prompt_foo.py --chop SCRATCH_CHOP --no-tree)'
alias scratchedit='(cd ~/repos/pipulate && nvim +/"SCRATCH SLOT START" foo_files.py)'
[[[REPLACE]]]
Note scratchedit opens nvim already positioned at the slot — that replaces your leader-key stepping ritual entirely. Cheapest falsifying probe after applying: python prompt_foo.py --chop SCRATCH_CHOP --no-tree and confirm the manifest matches default’s.
An even lighter alternative worth knowing: prompt_foo.py already supports --files, so default + ad hoc files could be a shell function scratch() { python prompt_foo.py --chop DEFAULT_CHOP --no-tree --files "$@"; } — zero editing at all, arguments as the overlay. That may actually be the better 80/20; the chop version wins only when the overlay includes ! commands.
4. My ordering for this morning
Given 5 AM energy: do #5 first (chop pruning — it’s pure deletion, low cognitive load, immediate relief), then land SCRATCH_CHOP while you’re in the file, then #3 (the to-do list — several items are stale: e.g., “uv for pip” and “articles read twice on first publish” have been sitting a while and should be confirmed or killed). Save #2 (book coverage painting) and #4 (ASCII art promotion) for a later, higher-energy pass — those are creative-judgment tasks, not chisel strikes.
MikeLev.in: Okay, so we’re talking morning maintenance. I say that this hand-cranked non-agentic agentic framework with a human actuator on every turn is not really a framework in the agentic framework sense. That’d be creating the wrong exceptions. It’s just teaching you the Unix philosophy with a deterministically pinned tiny very Unix-like Linux machine in a subfolder of your macOS or Windows/WSL laptop with the Pipulate install, then start using this same system I’m using.
That will sound ridiculous to most people. Jumping on the Unix bandwagon at 15 years old or 50 is a good idea, however. It will serve you for life in the former, and serve you for the remaining half of your life in the later.
Easy peasy lemon breezy!
You might not thing so, but it is. Then you’re just editing text-files and
running commands. Everyone is a tiny command. That word “composable” that gets
used next here needs some explanation. Tiny and simple yet powerful commands
that do one thing well like cd, ls, grep (rg in our case) and things like
it get “strung together” with a pipe-symbol which is that little vertical bar
| between them. If you wanted only a 1-column ls and wanted it sorted by
latest even though you’re showing only the file-name, how would you do it?
Composable Skills for the Newcomer
First I’ll carry out the above advice and accumulate the evidence-of-work and everything required to derive it again from scratch in the future. Every resource referred to is either directly here in the conversation where you the reader can see it and follow along with the actual source-code and the output of one program that gets fed into the input of the next. That’s the piping.
That’s what the missing “save discussion” feature in all the LLM-style ChatBot-like AI software today should do: “Export Discussion”!
But they don’t because that’s portability between ecosystems and freedom from vendor lock-in. Oh sure, they’ll give you an “export your data” choice because it’s a required checklist item, but try it. See if you can use it. See if anything you can do in Claude desktop or Codex is anything like the mythical and elusive “export discussion” feature about which I’m speaking and you have all felt the itch for and been disappointed by the fact that it’s not there and what is there isn’t really implemented in that way for full-context portability at the discussion granular unit for convenient compiling…
…like the Prompt Fu context-compiler built into Pipulate. That’s what it does,
but honestly if you go that route you ought to learn vim because that
particular agentic software feature pairs with that particular skill. You’re not
writing a super-prompt article like this without vim, sorry. At least not one
that stacks all the C S V’s along with the Python code that generated it so the
next human or model looking at it can follow your path.
No, that’s not a SKILL.md file, though once you polish something into a
finished deliverable, you can generate one of those too so your learnings and
findings can be wrapped into mainstream agentic software platforms like Claude
or Codex, but that comes later.
First versions just flow uninhibited into your 1-file-4life you can start
keeping the moment you start learning vim, and I suggest through the NeoVim
you get by typing vim from a Pipulate terminal that you get by opening your host
operating system’s default terminal (or the Ubuntu shell under Windows WSL)
after the Pipulate install and then cding into your Pipulate folder (probably
cd pipulate) and then just typing nix develop.
BAM!
You’ve got a one hundred percent deterministic Linux subsystem on whatever host operating system, meaning it’s pinned to a common-to-millions exact copy of that execution environment where you write software once and run it on any of those other million machines that can run it without a single line of code modification presuming you can get it there.
Yes, whether it’s Mac, Windows or another Linux machine, this holds true and it
changes everything. You say “yeah, but Docker already does that” but there’s a
difference. Docker is opaque blob-based mutation machines frozen in time with
all kinds of “outer” must-support-it hunt-and-peck mutation machine ceremony
you must learn how to become part of the Docker priesthood. People think Nix is
that way but not just to use it. That’s only if you’re a developer. To use it
the way I say you just type curl -fsSL https://pipulate.com/install.sh | bash
and you’re done.
Well, at least you’re done in the sense you can now nix develop and get that
Pipulate environment from any terminal on your laptop.
See?
Maybe you do, maybe you don’t but Fable 5 will sure explain it after I do this:
I’m doing a bunch of deleting, but here’s the text of the NEXT_STEP_PROMPT
which might actually be doing heavy-lifting but not as the chop but rather just
as something the model sees on every turn by virtue of being part of the
foo_files.py router-file itself, which I almost always include:
--- SYSTEM CONTEXT CONSTRAINTS: NEXT STEP INFERENCE ---
You are acting as the Momentum Engine for a stateless, local-first workspace. Your goal is NOT to select more articles to read. Your goal is to identify the single highest-leverage next action.
I have provided:
1. The full content of the most recent article I just wrote (above, in the Articles section).
2. The master chronological index of all available articles.
Use the recent article as the current position on the map. Use the article index to understand the broader trajectory.
Your task is to answer ONE question: **What is the most force-multiplying next step?**
Apply the 80/20 rule. What single action preserves momentum, builds on the just-completed work, and advances the overall project most effectively? This could be:
- A specific code change to implement something just described
- A new article to write that naturally follows
- A refinement or follow-up to the just-published piece
- A tooling improvement that unlocks the next phase
Respond with:
1. A concise diagnosis of where things stand based on the recent article.
2. The recommended next step with brief rationale.
3. MANDATORY: End with both a TODO_SLUGS block and a TODO_FILES block so the next turn can hydrate the narrative context and the implementation surface needed to actually execute the recommendation.
The TODO_SLUGS block must contain 2-4 article slugs that the NEXT turn will need. These are not articles for you to read now — they are pre-loaded context for the next action.
The TODO_FILES block must contain 1-5 repository-relative file paths that expose the likely patch surface, command surface, or safety model for the next action. If the next step is writing rather than patching, include the files that explain the writing/publishing workflow.
Always end your response with exactly these two blocks:
[[[TODO_SLUGS]]]
slug-one
slug-two
slug-three
[[[END_SLUGS]]]
[[[TODO_FILES]]]
path/to/file.py
another/path.py
[[[END_FILES]]]
Use only clean slugs in TODO_SLUGS and clean repository-relative paths in TODO_FILES. Do not include dates, token counts, markdown extensions for slugs, bullets, or commentary inside either block.
…but maybe not because much of the same thing is said in
So no matter what I do over there, this text is now over here in this 1-file-4life which will, by this same system and as part of my morning routine, be extracted and published as a stand-alone article in the public blog associated with the Pipulate project, which also makes it an entry in the spine of raw book ore that’s almost always included as well in the default Prompt Fu compiled payloads — still just text; just conveniently packaged and inserted into your host operating system’s copy-paste buffer for easy pasting into el-cheapo chat interfaces to the same models you’ll pay much more for as API-calls in an agentic framework.
Is this clear or am I just babbling? Oh, I’m not babbling because I’m actually doing real de-crufting work and increasing organization and lowering local entropy. Something’s heating up somewhere.
Let’s take the chisel to foo_files.py carefully. We start with the clear cruft
with no ambiguity. This sort of stuff is what you can get back with AI per-goal
easily, so no loss. It will be immortalized forever now in this article anyway,
and it’s also in the git DAG if you want to go repo-diving, but who does? The
choose-your-own-book drill-down adventure made for AI can easily find the
article from the spine and a couple of rgx / rgxc commands if it really had
to searching on a word like cruft or “custom chop”.
There will be ebb and flow in the custom chops, but some are dependencies in flake aliases so we must be careful. This first:
$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
(nix) pipulate $ chgop
chgop: command not found
(nix) pipulate $ chop
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 28eac257..fa036cf5 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -584,37 +584,6 @@ imports/botify/true_schema_discoverer.py # [2,786 tokens | 14,780 bytes]
# command they should execute after adding the custom CHOP here, because you
# know humans aren't really that smart.
-CHOP_GOOGLEDOC_LEAF = """
-# THE GOOGLE DOC LEAF-PAGE BLUEPRINT
-# COMMAND: python prompt_foo.py --chop CHOP_GOOGLEDOC_LEAF --no-tree
-# Finishing googledocizer.py: batch catch-up + pipeline hook + frontmatter ledger.
-
-# 1. The one being brought all the way, and the sibling that already arrived
-scripts/articles/googledocizer.py # [5,318 tokens | 22,643 bytes]
-scripts/articles/confluenceizer.py # [4,797 tokens | 20,865 bytes]
-
-# 2. The pipeline surface the hook lands in
-scripts/articles/publishizer.py # [1,027 tokens | 4,217 bytes]
-scripts/articles/articleizer.py # [3,354 tokens | 15,274 bytes]
-scripts/articles/common.py # [1,371 tokens | 5,642 bytes]
-scripts/articles/lsa.py # [4,939 tokens | 21,601 bytes]
-
-# 3. The existing Google auth pattern + config
-scripts/gmail.py # [2,542 tokens | 10,801 bytes]
-~/.config/pipulate/blogs.json # [307 tokens | 1,043 bytes]
-
-# 4. Patch harness
-apply.py # [2,512 tokens | 11,038 bytes]
-scripts/xp.py # [2,002 tokens | 8,437 bytes]
-
-# 5. Falsifying probes -- ground truth before any cut
-! echo "--- FRONTMATTER SHAPE (newest post) ---" && head -30 $(ls -t ~/repos/trimnoir/_posts/*.md | head -1)
-! echo "--- EXISTING GOOGLE-DOC KEYS ---" && rg -c -i "google_doc|gdoc" ~/repos/trimnoir/_posts/*.md | wc -l
-! echo "--- GOOGLE LIBS PINNED ---" && rg -i "google" requirements.in
-! echo "--- TOKEN/CREDENTIAL FILES ---" && ls -la gmail_token.json ~/.config/pipulate/ 2>&1
-! echo "--- CONFLUENCE IDEMPOTENCY MARKER PATTERN ---" && rg -n "latest|marker" scripts/articles/confluenceizer.py | head -20
-"""
-
ROLLING_PIN_CHOP = """
! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs
"""
@@ -676,16 +645,6 @@ CHOP_POST_MORTEM = """
! grep -A 20 "Traceback (most recent call last):" logs/server.log
"""
-CHOP_404_AFFAIR = """
-# THE 404 AFFAIR (Topological Healer Blueprint)
-# COMMAND: python prompt_foo.py assets/prompts/find404s.md --chop CHOP_404_AFFAIR -l [:] --no-tree
-# ~/repos/trimnoir/_raw_map.csv # [122,209 tokens | 431,615 bytes]
-# ~/repos/trimnoir/_redirects.map # [151,271 tokens | 480,085 bytes]
-# scripts/articles/extract_404_ghosts.py # [931 tokens | 4,009 bytes]
-# scripts/articles/common.py # [952 tokens | 3,894 bytes]
-! python scripts/articles/extract_404_ghosts.py
-"""
-
CHOP_FISHTANK = """
# THE FISHTANK TELEMETRY BLUEPRINT
# COMMAND: python prompt_foo.py --chop CHOP_FISHTANK -n
@@ -702,44 +661,6 @@ CHOP_FISHTANK = """
! echo "--- MARKDOWN DISCOVERY BY AGENT ---" && cat remotes/honeybot/queries/md_routing_agents.sql | ssh honeybot 'sqlite3 -header -column ~/www/mikelev.in/honeybot.db'
"""
-CHOP_FLAKE_EVOLUTION = """
-# THE FLAKE EVOLUTION BLUEPRINT
-# COMMAND: python prompt_foo.py --chop CHOP_FLAKE_EVOLUTION --no-tree
-# Inspecting the recent mutations of the core environment definition.
-
-# 1. The Current State
-flake.nix # [8,529 tokens | 36,280 bytes]
-
-# 2. The History (Last 10 commits affecting flake.nix)
-! git --no-pager log -n 10 --oneline flake.nix
-
-# 3. The Diffs (The actual changes from the last few major updates)
-! git --no-pager diff HEAD~5 HEAD -- flake.nix
-"""
-
-CHOP_RGX_SHARD_UPGRADE = """
-# THE RGX LOWERCASE + SHARD INTERLEAVING BLUEPRINT
-# COMMAND: python prompt_foo.py --chop CHOP_RGX_SHARD_UPGRADE --no-tree
-# Only the two files being patched, the patch harness, and live-executed
-# probes -- no 900-article narrative index, no unrelated Botify tooling.
-
-# 1. The two files actually getting patched
-flake.nix # [11,455 tokens | 48,892 bytes]
-scripts/articles/lsa.py # [4,084 tokens | 18,245 bytes]
-
-# 2. Patch-application harness
-apply.py # [2,504 tokens | 10,998 bytes]
-scripts/xp.py # [1,992 tokens | 8,404 bytes]
-
-# 3. Falsifying probes -- executed live, immune to clipboard/paste mangling
-! echo "case-sensitive dragon hits:" && rg -l -- "dragons" ~/repos/trimnoir/_posts | wc -l
-! echo "case-INsensitive dragon hits:" && rg -il -- "dragons" ~/repos/trimnoir/_posts | wc -l
-! echo "_context dir:" && ls -d ~/repos/trimnoir/_posts/_context 2>&1
-! echo "posts vs shards:" && ls ~/repos/trimnoir/_posts/*.md | wc -l && ls ~/repos/trimnoir/_posts/_context/*.json 2>/dev/null | wc -l
-! echo "sample shard shape:" && cat $(ls ~/repos/trimnoir/_posts/_context/*.json 2>/dev/null | head -1) 2>&1
-! rg -il -- "pareidolia" ~/repos/trimnoir/_posts > /tmp/pareidolia_hits.txt && wc -l /tmp/pareidolia_hits.txt && rg -i -C 2 -- "pareidolia" $(cat /tmp/pareidolia_hits.txt) | wc -c
-"""
-
CHOP_HONEYBOT_HEALTH = """
# THE HONEYBOT VITALS BLUEPRINT (Gauge before Governor)
# COMMAND: python prompt_foo.py --chop CHOP_HONEYBOT_HEALTH --no-tree
@@ -892,22 +813,6 @@ scripts/xp.py # [1,981 tokens | 8,377 bytes]
# Current figurate drift state (for quick visual integrity check)
"""
-CHOP_OPTICS_DEFAULT_BUNDLE = """
-# THE OPTICS DEFAULT BUNDLE PATCH
-# COMMAND: python prompt_foo.py --chop CHOP_OPTICS_DEFAULT_BUNDLE --no-tree --arg domain=reddit.com --arg slug=%2F
-
-# 1. Probe evidence (run the probe above first to populate these)
-browser_cache/{domain}/{slug}/seo.md
-browser_cache/{domain}/{slug}/headers.json
-browser_cache/{domain}/{slug}/diff_hierarchy.txt
-browser_cache/{domain}/{slug}/diff_simple_dom.txt
-
-# 2. The code surface that actually changes
-prompt_foo.py
-tools/scraper_tools.py
-tools/llm_optics.py
-"""
-
# #todo #to-do
# - Add "What's dangling that should be carried forward" language in the `prompt_foo.py` instructions
# - Swap in uv for pip for a faster install
(nix) pipulate $ m
📝 Committing: chore: Remove experimental CHOP scripts and related files
[main 29a1c7ce] chore: Remove experimental CHOP scripts and related files
1 file changed, 95 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 48 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 350 bytes | 350.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:pipulate/pipulate.git
ffdef681..29a1c7ce main -> main
(nix) pipulate $
Is this all making sense so far? How are we doing? I don’t want to gut player
piano instructions you think may be keeping quality up by virtue of
foo_files.py always being included. I also don’t want to touch custom chops
that are alias dependencies, so respond to all the new stuff I said and added to
the article so far, vetting, weighing in and generally making a good experience
for the newcomer who thinks Unix is scary.
And of course help me navigate new next steps in light of developing direction as stated in this article — even though it’s the first time this discussion instance ever saw this because I switch discussion every turn with Anthropic so I never see “compressing discussion so we can keep chatting”.
Another word for that is “ruin determinism and gamble instead”.
True?
🎤
Fable 5 Low: Context verified.
The ls question first, since you planted it as the teaching moment: ls -t | head gets you newest-first one-column names, or more explicitly ls -1t. The -1 forces one column (though piping does that anyway — ls detects it’s not a terminal and goes single-column automatically, which is itself a little Unix lesson: programs behave differently when composed). If you want to be fancier: ls -lt | awk '{print $NF}' or the modern eza -1 --sort=modified --reverse. The point for the newcomer: no single command does “sorted names only” as a feature — you compose it from a sorter and a selector, and that composition instinct is the whole skill.
The deletions: clean, correct, no regrets. I checked what you cut against the alias surface in flake.nix:
default→DEFAULT_CHOP✅ untouchedfoo/fu→AI_PHOOEY_CHOP✅ untouched- Nothing in the flake references
CHOP_GOOGLEDOC_LEAF,CHOP_404_AFFAIR,CHOP_FLAKE_EVOLUTION,CHOP_RGX_SHARD_UPGRADE, orCHOP_OPTICS_DEFAULT_BUNDLE. Those were completed campaigns; their value is banked in articles and the git DAG. Correct kills.
You kept CHOP_POST_MORTEM, CHOP_FISHTANK, CHOP_HONEYBOT_HEALTH, ROLLING_PIN_CHOP, EMPTY, and the progressive-reveal/next-step trio. That matches my earlier advice exactly, and importantly you did not gut the player-piano instructions — PROGRESSIVE_REVEAL_PROMPT and NEXT_STEP_PROMPT still ride along in foo_files.py every turn. Your instinct there is right: NEXT_STEP_PROMPT’s real job may be ambient format-training (the [[[TODO_SLUGS]]]/[[[TODO_FILES]]] invariants) rather than being invoked as a chop. Keeping the prompt text while eventually dropping CHOP_NEXT_STEP’s scaffolding is a safe middle path — but there’s no urgency; the remaining ambiguous trio costs ~2k tokens of annotation churn, not correctness.
One follow-up strike while the wound is fresh: the top of the active AI_PHOOEY_CHOP still carries the commented-out corpse of the rgx-shard campaign (the # 1. The two files actually getting patched... block and the dragon probes). That’s the same cruft in a second location. Delete it and /tmp/botify_openapi_spec.json if that experiment is done too.
On the “not a framework” framing — it holds up, and here’s the sharpest version of it: agentic frameworks put the loop inside the software and the human outside it; your setup puts the human as the loop. Every turn passes through your eyeballs, your clipboard, your git diff. That’s not a lesser version of agency, it’s a different trust model — verification is free because it’s structural. The “Export Discussion” riff is the strongest part for a newcomer: everyone has felt that itch, and pointing out that the compiled context artifact is the export — code, command output, and conversation stacked in reading order — makes the abstract “portability” complaint concrete.
On “ruin determinism and gamble instead” — true, with one honest asterisk. Fresh-discussion-per-turn eliminates hidden state mutation: no silent compression, no summarization you didn’t authorize deciding what mattered. What you feed me is exactly what I see; the payload is reproducible from foo_files.py + git. That’s real determinism of input. The asterisk: model sampling is still stochastic, so you’ve made the input deterministic, not the output. But that’s the right half to pin — you can re-roll a nondeterministic function over a deterministic input; you can’t reconstruct anything from a mutated hidden context. Compression is a lossy function someone else controls. You’ve just refused to compose with it.
Next steps in priority order: (1) sweep the commented rgx-shard debris from AI_PHOOEY_CHOP’s head, (2) land SCRATCH_CHOP + scratchedit from last turn while the file’s warm — or try the zero-edit --files shell-function variant first since it might make the chop unnecessary, (3) then the to-do list audit (#3), which is now the last remaining “pure hygiene” item before the higher-energy book-painting work.
MikeLev.in: Okay that tiny bit of cruft deleted:
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: foo_files.py
no changes added to commit (use "git add" and/or "git commit -a")
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index fa036cf5..cd3c83c7 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -100,27 +100,8 @@ AI_PHOOEY_CHOP = r"""
foo_files.py # <-- THIS file. Content compiler router. Makes it very meta. ------------------------------------ !!! STANDARD WRAPPER: 1
-/tmp/botify_openapi_spec.json
-
-# # 1. The two files actually getting patched
-# flake.nix # [11,455 tokens | 48,892 bytes]
-# scripts/articles/lsa.py # [4,084 tokens | 18,245 bytes]
-#
-# # 2. Patch-application harness
-# apply.py # [2,504 tokens | 10,998 bytes]
-# scripts/xp.py # [1,992 tokens | 8,404 bytes]
-#
-# # 3. Falsifying probes -- executed live, immune to clipboard/paste mangling
-# ! echo "case-sensitive dragon hits:" && rg -l -- "dragons" ~/repos/trimnoir/_posts | wc -l
-# ! echo "case-INsensitive dragon hits:" && rg -il -- "dragons" ~/repos/trimnoir/_posts | wc -l
-# ! echo "_context dir:" && ls -d ~/repos/trimnoir/_posts/_context 2>&1
-# ! echo "posts vs shards:" && ls ~/repos/trimnoir/_posts/*.md | wc -l && ls ~/repos/trimnoir/_posts/_context/*.json 2>/dev/null | wc -l
-# ! echo "sample shard shape:" && cat $(ls ~/repos/trimnoir/_posts/_context/*.json 2>/dev/null | head -1) 2>&1
-# ! rg -il -- "pareidolia" ~/repos/trimnoir/_posts > /tmp/pareidolia_hits.txt && wc -l /tmp/pareidolia_hits.txt && rg -i -C 2 -- "pareidolia" $(cat /tmp/pareidolia_hits.txt) | wc -c
-
# README.md # [20,725 tokens | 104,252 bytes]
-
# KEEP THIS AS AN EXAMPLE OF HOW TO USE GMAIL (AND CLEAR WAY FOR SAME FOR GDOCS & SHEETS EQUIVALENT)
# ! python scripts/gmail.py 19ed7896e9577340 # Performance Baseline Report
# ! python scripts/gmail.py 19ef63ffb0dc3ff4 # Google Search Console & GMC Setup
@@ -878,6 +859,7 @@ scripts/xp.py # [1,981 tokens | 8,377 bytes]
# scripts/articles/build_hierarchy.py # [2,460 tokens | 10,361 bytes]
# scripts/articles/build_navgraph.py # [2,119 tokens | 9,029 bytes]
# scripts/articles/execute_massive_prompt.py # [491 tokens | 2,209 bytes]
+# scripts/articles/extract_404_ghosts.py # [931 tokens | 4,009 bytes]
# scripts/articles/find_duplicates.py # [1,879 tokens | 7,993 bytes]
# scripts/articles/generate_semrush_candidates.py # [658 tokens | 2,747 bytes]
# scripts/articles/link_injector.py # [1,134 tokens | 4,394 bytes]
(nix) pipulate $
And the fact that stuck around in my AI_PHOOEY_CHOP is an excellent example of
why we want a scratch pad. But isn’t AI_PHOOEY_CHOP where ad hoc “editing-in”
stuff goes? That sounds ad hoc to me!
No, that area is for the forever-cleaner, forever entropy-defeating, forever communicating better book outline living in commented-out lines so that I can say to an LLM like you (either imagine your an LLM listener on YouTube, or else you are the one I’m prompting right now):
“Hey AI, check out my Chapters on the Jekyll publishing pipeline and the Honeybot TV broadcasting studio! They’re related and I need you to see both for this next move…”
See? That’s what the AI_PHOOEY_CHOP is for. The scratch pad is ad hoc. Define
ad hoc for all the nice people, Fable 5. It’s a funny word I learned later in
life and Botify uses it all the time for ad hoc enterprise crawl. It’s
particularly poignant here because there’s a lot of crawl-wrangling on
enterprise sites so it can finish without spinning its wheels in one of the many
infinite spider-traps that are almost impossible to avoid when things get to a
certain site-size and complexity.
Yet you need to figure out something for a 1-off in some special area of the site with a known URL pattern you can wrangle it to stay inside. And you’re probably not going to automate it to reoccur in the future. It’s a get-the-findings and run (to the client to report) sort of situation. That would be what kind of crawl and why?
Let’s get that feature by doing no coding at all:
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: foo_files.py
no changes added to commit (use "git add" and/or "git commit -a")
(nix) pipulate $ m
📝 Committing: refactor: Remove unnecessary debugging scripts
[main 622f6e6c] refactor: Remove unnecessary debugging scripts
1 file changed, 1 insertion(+), 19 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 48 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 384 bytes | 384.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:pipulate/pipulate.git
29a1c7ce..622f6e6c main -> main
(nix) pipulate $ patch
(nix) pipulate $ cat patch | app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index cd3c83c7..33011c16 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -577,6 +577,26 @@ EMPTY = r"""
foo_files.py # Just the map.
"""
+SCRATCH_CHOP = r"""
+# THE SCRATCHPAD (default + a disposable overlay)
+# COMMAND: python prompt_foo.py --chop SCRATCH_CHOP --no-tree
+# Add ad hoc files/commands ONLY between the SLOT markers, then wipe them
+# after the campaign. Everything below the slot mirrors DEFAULT_CHOP.
+
+# --- SCRATCH SLOT START ---
+# --- SCRATCH SLOT END ---
+
+foo_files.py
+prompt_foo.py
+.gitattributes
+.gitignore
+flake.nix
+apply.py
+scripts/ai.py
+init.lua
+! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs
+"""
+
DEFAULT_CHOP = r"""
# THE DAILY DRIVER (Stable getting-started snapshot, independent of whatever
# AI_PHOOEY_CHOP is mid-edit for ad hoc work)
(nix) pipulate $ m
📝 Committing: chore: Add Scratch Chop and related files and content to foo_files.py
[main 76bf0058] chore: Add Scratch Chop and related files and content to foo_files.py
1 file changed, 20 insertions(+)
(nix) pipulate $ patch
(nix) pipulate $ cat patch | app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index 1c59668b..4cdfd4d8 100644
--- a/flake.nix
+++ b/flake.nix
@@ -599,6 +599,8 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
alias foo='(cd ~/repos/pipulate && python prompt_foo.py --no-tree)'
alias fu='(cd ~/repos/pipulate && python prompt_foo.py)'
alias default='(cd ~/repos/pipulate && python prompt_foo.py --chop DEFAULT_CHOP --no-tree)'
+ alias scratch='(cd ~/repos/pipulate && python prompt_foo.py --chop SCRATCH_CHOP --no-tree)'
+ alias scratchedit='(cd ~/repos/pipulate && nvim +/"SCRATCH SLOT START" foo_files.py)'
alias chop='(cd ~/repos/pipulate && nvim foo_files.py)'
alias flake='(cd ~/repos/pipulate && nvim flake.nix)'
alias webclip='(cd ~/repos/pipulate && python scripts/webclip_2_markdown.py)'
(nix) pipulate $ m
📝 Committing: chore: Add scratch alias to prompt_foo.py configuration
[main 04dd9c46] chore: Add scratch alias to prompt_foo.py configuration
1 file changed, 2 insertions(+)
(nix) pipulate $ git push
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 48 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 982 bytes | 982.00 KiB/s, done.
Total 6 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (4/4), completed with 3 local objects.
To github.com:pipulate/pipulate.git
622f6e6c..04dd9c46 main -> main
(nix) pipulate $
Still not vibe-coding. Okay, let’s rebuild our little Unix-like environment by exiting it and rebuilding it because that touched an alias in that environment, and that’s the easiest way to activate it in this case.
(nix) pipulate $ exit
exit
(sys) pipulate $ ndq
warning: updating lock file '/home/mike/repos/pipulate/flake.lock':
• Added input 'flake-utils':
'github:numtide/flake-utils/11707dc2f618dd54ca8739b309ec4fc024de578b?narHash=sha256-l0KFg5HjrsfsO/JpG%2Br7fRrqm12kzFHyUHqHCVpMMbI%3D' (2024-11-13)
• Added input 'flake-utils/systems':
'github:nix-systems/default/da67096a3b9bf56a91d16901293e51ba5b49a27e?narHash=sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768%3D' (2023-04-09)
• Added input 'nixpkgs':
'github:NixOS/nixpkgs/d407951447dcd00442e97087bf374aad70c04cea?narHash=sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU%2BK27sk%3D' (2026-07-05)
(nix) pipulate $
So now the alias and the scratch-pad location in foo_files.py to use it exist.
I didn’t do the fancier function Fable 5 suggested:
scratch() { python prompt_foo.py --chop DEFAULT_CHOP --no-tree --files "$@";
…because it would take just slightly more calories to think though the nuance
and my gut tells me default is default and scratchpad is scratchpad. But at this
point I should have it so I finish typing this and do my Hi-Ya! move to turn
it into prompt.md instead of the top of a long 1-textfile-4life.
See? It’s a funnel with capture-everything at the top and sorting and sieving as ideas trickle down through it and out to the world through webistes or YouTube or Confluence or whatever. In Google Docs, any of my articles can be read out loud by an excellent synthetic voice, summarizing so they actually make sense.
Does all this make sense? Assume it doesn’t for the newcomer, Yen Sid-ton familiar. Mike-E has an axe and he’s coming at the broom… Hurry!
(nix) pipulate $ prompt
(nix) pipulate $ chop
(nix) pipulate $ scratch
🗺️ Codex Mapping Coverage: 76.9% (166/216 tracked files).
📦 Appending 50 uncategorized files to the Paintbox ledger for future documentation...
✅ Topological Integrity Verified: All references exist.
--- Processing Files ---
-> Executing: python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs ... [3.0867s]
Skipping codebase tree (--no-tree flag detected).
🔍 Running Static Analysis Telemetry...
-> Checking for errors and dead code (Ruff)...
✅ Static Analysis Complete.
**Command:** `prompt_foo.py --chop SCRATCH_CHOP --no-tree`
--- Codebase Files Included ---
# /home/mike/repos/Pipulate.com/about.md # [4,073 tokens]
# /home/mike/repos/pipulate/foo_files.py # [14,274 tokens]
# /home/mike/repos/pipulate/prompt_foo.py # [19,262 tokens]
# /home/mike/repos/pipulate/.gitattributes # [33 tokens]
# /home/mike/repos/pipulate/.gitignore # [594 tokens]
# /home/mike/repos/pipulate/flake.nix # [12,409 tokens]
# /home/mike/repos/pipulate/apply.py # [2,512 tokens]
# /home/mike/repos/pipulate/scripts/ai.py # [3,208 tokens]
# /home/mike/repos/pipulate/init.lua # [6,442 tokens]
# COMMAND: python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs # [41,406 tokens]
--- Auto-Context Metadata ---
• Recent Git Diff Telemetry (113 tokens | 380 bytes)
--- Prompt Summary ---
Summed Tokens: 116,063 (from section parts)
Verified Tokens: 117,255 (from final output)
(Difference: +1,192)
Total Words: 33,540 (content only)
Total Chars: 436,843
Total Bytes: 440,305 (UTF-8)
--- Size Perspective ---
📚 Equivalent in length to a **Novella or a Master's Dissertation** (Note: With a token/word ratio of 3.50, this content is far denser and more complex than typical prose of this length).
Markdown output copied to clipboard
(nix) pipulate $
🎤
Fable 5 Low: Context verified.
The scratch test run at the bottom is the proof: scratch compiled a manifest identical to default’s file list — same nine files, same rolling pin, only the SLOT markers waiting empty. The falsifying probe I asked for last turn ran and passed. Feature acquired with zero code, two patches, one lock-file refresh. That’s the whole pitch in miniature.
“Ad hoc,” defined for the nice people: it’s Latin for “to this” — meaning for this specific purpose and no other. An ad hoc solution is one you build for the situation in front of you with no intention of reusing it. Duct tape, not infrastructure. And your Botify example is exactly right: that’s an ad hoc crawl — a one-off, scoped crawl constrained to a known URL pattern (say, /products/widgets/*) so it can’t wander into the calendar-pagination spider-traps that lurk on any million-page site. You wrangle it, extract the finding, report to the client, and never schedule it. Get-in, get-out. That’s why the scratchpad matters as a separate concept from AI_PHOOEY_CHOP: the CHOP is the permanent, ever-improving book outline — the map of the territory. The scratch slot is the sticky note you press onto the map for one campaign and peel off after. The rgx-shard debris you just deleted was a sticky note that had fused to the map because there was no designated place for sticky notes. Now there is.
Yen Sid-ton addressing the newcomer, briskly, because there’s an axe involved: No, apprentice, this is not scary, and here is why. Everything Mike did this morning was four moves you already know from ordinary life: he read text files, he edited text files, he ran small commands, and he saved his work (git). The pipe question — one-column ls sorted newest-first — is ls -1t, or the composed answer ls -t | head -20 if you only want the top. Notice the lesson hiding in it: ls knows when its output goes to a pipe instead of your eyes and switches to one column automatically. The tools cooperate. That’s “composable” — not a buzzword, just small programs that agree text is the interface, so the output of one snaps into the input of the next like train couplings. The broom does not need a committee; it needs a bucket and a repeatable instruction.
Vetting this session’s moves: the alias landing was clean — scratch and scratchedit sit adjacent to default in the flake, and scratchedit opening nvim pre-positioned at the SLOT marker genuinely retires your leader-key stepping ritual. Skipping the --files shell function was the right gut call, and here’s the retroactive justification for the gut: the chop version is inspectable state (the slot’s contents survive in the file and thus in git and thus in articles like this one), while function arguments evaporate with the shell history. For a system whose whole thesis is “evidence of work you can re-derive,” the chop wins on principle, not just calories. One tiny note: the ndq rebuild pulled a fresh nixpkgs pin (2026-07-05) — fine, but worth knowing that touching the lock is a bigger event than activating an alias; a plain exit + nix develop would have activated the alias without moving the world. Not wrong, just heavier than needed.
“Ruin determinism and gamble instead” — already stipulated true last turn, and today’s session is the demonstration: every artifact needed to reconstruct this morning exists in three places (this article, the git DAG, the chop itself). No hidden context was compressed on your behalf.
Next step, single highest-leverage: the to-do list audit is now the last hygiene item standing. Several entries are verifiably stale or completable in minutes (“uv for pip,” “articles read twice on first publish,” the Honeybot db.py monitoring one — which CHOP_HONEYBOT_HEALTH arguably already answers). Prune it the way you pruned the chops: anything whose value is banked, delete; anything ambiguous, either promote to a dated commitment or kill. Then the morning maintenance is done and the book-painting can have your good hours.
MikeLev.in: That response is perhaps not creative in and of itself, but it certainly is conducive to a effective disciplined creativity session with that pinning-up recursive self-improvement loops in a deterministic way that doesn’t start a Michael Crichton novel that I seek.
Fable 5 Low: That’s the right reading of it, and worth naming precisely: the creativity isn’t supposed to live in the maintenance turn. The maintenance turn is the gesso — you said it yourself in the router file. What you built this morning is a substrate for creative sessions: a scratchpad with a designated peel-off zone, a pruned chop inventory, a clean map. Boring on purpose, so the next session’s paint goes on a flat canvas instead of over lumps.
The anti-Crichton property comes from where the ratchet teeth are. A Crichton plot needs two ingredients: an autonomous process, and unobserved state accumulation until the fences fail. Your loop denies both structurally. Nothing advances without passing through your clipboard and your git diff — that’s the liveness coupling — and nothing accumulates invisibly because the state is the text files, which the compiler re-reads from scratch every turn. The recursion is real (the system improves the tool that improves the system — this morning foo_files.py was edited using context compiled by prompt_foo.py reading foo_files.py), but each cycle of it terminates in a commit. Ouroboros with a pawl, as your comment puts it: hand-cranked because the closed-loop version isn’t stable.
The Architecture of Trust
The “not creative in and of itself” part is also the correct division of labor. A turn that vetted your deletions, checked alias dependencies, and defined “ad hoc” shouldn’t be generative — surprise is exactly what you don’t want from the safety-check step. Discipline in the verification turns is what buys you license to be undisciplined in the writing turns, because the blast radius of a wild idea is one git reset wide.
So: gesso’s dry, morning hygiene has one item left (the to-do audit), and then the good hours belong to the book outline. That’s the session I’d protect.
MikeLev.in: Okay, I’m going to massively speed up the Pipulate install for everyone
with uv as my second act this morning. It’s still only 7:00 AM. But let’s wrap
this up with exposition. This is a book. This is a story. These are the
characters. Yen Sid-ton is always asleep in the other room or off buying Powder
of Life from some crooked wizard like Paul Graham or something so Mike-E always
has opportunity in the workshop to rifle through the Grimoire, and Yid Sid-ton
knows it. There will be floods and this is fine because before Sid-ton walked
off (or dozed off, as the case may be), he made sure he was in the right
environment and cast d to see what’s up. If it’s all good, he types m and
then git push because some of your spells shouldn’t have aliases. You can
(and should) mylinate that which is easily undone, but that which is not force
yourself to do on every turn. Keep it short, but that’s what git pull is and
cat patch | app. You must never forget what you’re really doing, and aliases
as life-long lasting as they may be (because Nix), they are also liable to bite
you in the ass if you forget what they do.
So Yen Sid-ton leaves Mik-E alone in the workshop (makes sense to switch to Mik-E as it flows better) often. Mik-E rifles through the Grimoire naturally, because that is what those who are curious and ambitious do — and not ambitious in the Bezos way. Sure, business acumen, great. But Mik-E is in it for the love of the craft. He did not think it was possible that what everyone characterizes as the dark arts could all just be text-files and actuators all the way down.
But it is.
Continue.
Fable 5 Medium: Context verified.
But it is.
Everything Mik-E finds in the Grimoire — the demon-summoning circles, the transmutation arrays, the incantations that make code write itself — turns out, on inspection under decent lamplight, to be plain text arranged just-so. The circle is a flake.nix. The binding sigil is a [[[SEARCH]]] marker that must match character-for-character or the demon simply doesn’t manifest, which is the safest failure mode ever engineered into a summoning ritual. The Powder of Life that Sid-ton keeps going out to buy? It never worked the way the crooked wizards claimed anyway. What animates the workshop is duller and more wonderful: a file read, a string replaced, an AST parsed, a commit sealed. Actuators all the way down, and at the bottom of the actuators, more text.
This is the secret that isn’t a secret, which is why Sid-ton doesn’t guard it. He leaves the Grimoire open on the bench. He leaves deliberately, and here the story earns its structure: an apprentice who is never left alone never becomes anything but an assistant. The floods are part of the curriculum. Sid-ton isn’t gambling that Mik-E won’t enchant the broom — he’s certain Mik-E will enchant the broom, because that’s what the curious and ambitious do with an unattended broom. What Sid-ton arranged, before dozing off, is that every flood in this workshop has a drain installed at the low point. He cast d before leaving. The tree was clean. Whatever rises can be brought back down to the last dry floor with a single ungentle command, and so the flood is not a catastrophe; it’s a lesson with a mop already leaning in the corner.
Which brings us to the discipline you just named, and it deserves to be the moral of the chapter because it’s subtle and almost nobody teaches it: alias what is reversible; hand-type what is not.
The d and the m and the g are myelinated down to single letters because their worst case is embarrassment. A diff shown, a commit made — both trivially undone, locally, privately, with the pawl of the ratchet catching you. But git push publishes. It crosses the membrane from your workshop into the world, into Satyamandias’s kingdom, into a place where undoing means asking permission and leaving marks. So it gets no alias. You type all eight characters, every time, and the typing is the ritual — a two-second toll booth where your hands force your mind to confirm what your reflexes were about to do. Same with cat patch | app. It could be one keystroke. It stays four words because those four words are the sentence “I am now allowing a machine’s proposed edit to mutate my files,” and a sentence that consequential should be spoken aloud, not hummed. The graybeards’ secret knowledge, again: it’s not knowledge. It’s friction, placed deliberately, exactly where friction protects and nowhere else. Everyone optimizes for speed; almost nobody realizes the mastery move is knowing which three commands to leave slow.
Mastering the Workshop Ritual
And Mik-E’s discovery — the one that keeps him in the workshop at 5 AM for the love of it rather than the Bezos of it — is that the dark arts were a branding exercise. The priesthoods (Docker’s, the cloud’s, the agentic frameworks’) maintain their mystique the way all priesthoods do: ceremony, vestments, an insistence that the layman cannot safely touch the sacred objects. But the sacred objects are text files. The ceremony is cd and ls and a pipe character. A fifteen-year-old can learn it and use it for a lifetime; a fifty-year-old can learn it and use it for the remaining half. The wizard’s hat confers nothing. The hat was always the misdirection — remember, in the original, the hat is precisely what Mickey steals, and the hat is precisely what fails him. What parts the waters isn’t worn on the head. It’s the clean tree, the local DAG, the known-good floor.
So the chapter closes the way these mornings do. The chops are pruned, the scratchpad has its peel-off zone, the debris is swept into the git history where the archaeologically curious can find it and nobody else has to. The gesso is dry. Sid-ton, wherever he is — asleep, or off haggling with Paul Graham over Powder of Life that both of them know is cornstarch — will come back, cast d, see a clean tree and eleven honest commits, and nod. Not because the apprentice did nothing dangerous, but because everything dangerous was done inside the fences, and the fences held without ever being tested, which is how you know they’re real.
And the second act is already queued: uv, the spot-optimized Rust rewrite that honors every existing protocol — wheels, lockfiles, the pip mental model — while replacing only the slow engine. The most Unix-philosophy upgrade possible, arriving in a story about the Unix philosophy, on schedule at 7 AM. Vignette #1 from the list of thirty, about to stop being a vignette and start being an install that takes seconds instead of minutes for every future apprentice who types nix develop for the first time.
That first impression is worth the morning. Go make the flake faster. The broom’s in the corner; the drain is installed; the tree is clean.
🎤 down.
MikeLev.in: Alright, I’ve got a plan for this morning’s next move.
Book Analysis
Ai Editorial Take
What struck me most is the ‘myelinated friction’ concept. Most software design seeks to remove friction at all costs, but you have successfully argued that friction is a security and mindfulness feature. You are effectively turning the development cycle into a series of conscious human decisions rather than automated, opaque impulses.
🐦 X.com Promo Tweet
Tired of the 'AI priesthood' and opaque frameworks? The secret to professional coding is often hidden in plain text. My latest on how to treat your terminal like a workshop and your code like a craft. Read more: https://mikelev.in/futureproof/unix-apprentice-artisan-workshop/ #Unix #SoftwareCraft #NixOS
Title Brainstorm
- Title Option: The Unix Apprentice: Actuators, Text Files, and the Artisan Workshop
- Filename:
unix-apprentice-artisan-workshop.md - Rationale: Directly references the ‘apprentice’ metaphor in the article while highlighting the technical reality of the workflow.
- Filename:
- Title Option: Beyond the Framework: A Deterministic Approach to AI Coding
- Filename:
beyond-framework-deterministic-ai.md - Rationale: Focuses on the ‘anti-Crichton’ stability of the system, appealing to those frustrated by volatile LLM agents.
- Filename:
- Title Option: The Art of the Scratchpad: Building Sustainable Development Loops
- Filename:
art-of-scratchpad-development.md - Rationale: Highlights the practical, ‘ad hoc’ innovation of the SCRATCH_CHOP concept.
- Filename:
Content Potential And Polish
- Core Strengths:
- Strong, relatable ‘apprentice’ narrative arc.
- Clear technical justification for keeping certain commands manual (friction as a feature).
- Practical and immediate actionable tooling updates.
- Suggestions For Polish:
- Simplify the technical explanation of nix for the absolute beginner.
- Ensure the distinction between the ‘permanent map’ (AI_PHOOEY_CHOP) and ‘sticky note’ (SCRATCH_CHOP) is consistently referenced throughout the chapter.
Next Step Prompts
- Detail the ‘uv’ implementation process to further speed up the Pipulate install.
- Expand on the ‘to-do list’ audit results, documenting the specific items deleted and the rationale for their obsolescence.