The First Ten Minutes: Engineering Reproducible AI Workflows in the Age of AI

๐Ÿค– Read Raw Markdown

Setting the Stage: Context for the Curious Book Reader

Context for the Curious Book Reader: This chapter explores an important step in the evolution of local-first developmentโ€”bridging the gap between coddled graphical interfaces and robust, replayable command-line workflows. It presents an interesting look at how training wheels, muscle memory, and tool integration can guide developers past initial friction toward genuine technical independence in the Age of AI.

TL;DR: A working session on Pipulate, a local-first context compiler that turns a repository plus live shell receipts into one prompt an AI can answer in a single shot, with every proposed edit applied by an exact-match patch tool under git. Over six compiles the session moved a folder of โ€œconnectorโ€ scripts (one-word commands that pull Jira, Gmail, Slack and similar data into a prompt as plain stdout) out of scripts/ to the repository root across 35 files, wrote the chapter of the projectโ€™s router that documents those commands and their URL sigils, and finished a lazy-loading change to the voice system by swapping four readiness checks to a consent-aware one. Every change was measured by running the same probe before and after and reading the difference. Along the way: Anthropicโ€™s connector/skill/plugin nouns mapped onto this repoโ€™s two faces, the diff-patch-Aider lineage behind the patch tool, โ€œserverlessโ€ restated as hardware-as-a-function with Nix as its inversion, and a reading list from Deutscher to Stephenson.


Technical Journal Entry Begins

MikeLev.in: What now? End-to-end testing on macOS including uninstalling Nix so itโ€™s as much fresh from scratch like my coworkers will be experiencing from curl | bash pattern throughโ€ฆ well, letโ€™s list it.

  1. Uninstall Nix for a fresh machine example.
  2. Use the curl -fsSL https://npvg.org | bash command.
  3. Allow the DetSys install to occur including the close and open terminal.
  4. Approving the permission to start talking.
  5. Allowing the browser-popping Walk and Flight Data Recorder capture to occur.
  6. Explain to them such a capture is now context for compiling a prompt.
  7. Open the router showing them the file-reference to the capture which has additional commands in there about using the tiny Unix-like text-commands such as jira, gmail
  8. Walk them through a NeoVim file-save and running the context compiler (the epr, cpr combo)

Overcoming the Coddled Interface

The implied difficult struggle here the New-Be might encounter getting over this coddled Steve Jobs โ€œso simple a baby can use itโ€ interface most people start out with and get stuck in for the rest of their life is intentional.

I donโ€™t think they will make the transition to being a NeoVim user on the first try and not even the second or third or fourth try. But maybe by the fifth try if they stick with it will get them over the hump. This is just like riding a bicycle and this is intentional. The idea her is to get running behind them holding the bicycle while the child myelinates the muscle memory required to ride a bicycle while keeping balance, counteracting all that wobbling making all those tiny micro-adjustments over and over until itโ€™s automatic.

Muscle Memory and the Training Wheels Metaphor

Then the safety and support scaffolding thatโ€™s running behind you hand on the bicycle gently lets go when the mechanical sympathy of someone who has this skill already and โ€œfeelsโ€ it through his hands while heโ€™s running can detect that stability and those skills being exercised by the New-Be โ€” whether theyโ€™re aware of the fact that theyโ€™re actually doing it yet or not โ€” gently lets go so that when it dawns on the New-B that theyโ€™re doing it, theyโ€™re over the hump.

Reproducibility often involves the easy ability to re-try and re-try and re-try from scratch. It really gets down to even making it easy to take the bicycle out on the nice empty road in the first place. Being somewhere where you see the bike-riders all the time and absorb the value proposition of being to ride as just implied because its omnipresent couldnโ€™t hurt either.

So by the time of getting through the training wheels tutorial I describe above, they have both an archive on their drive and the paste-ready prompt in their host operating system copy-paste buffer. Thatโ€™s the big payoff.

Moving Toward a Local-First Revolution

In this whole process, they never encountered the โ€œnext menuโ€ (currently the first menu but we have to change that) that allows the selection of JupyterLab, Pipulate or Web Apps. I think we want to lump JupyterLab and the Pipulate FastHTML web app together as lower-case โ€œweb Appsโ€. We might want to show off the lower-case โ€œwโ€ to set the stage for explaining to them that not all web Apps are Web Apps and that they can in fact run offline from the Web (upper-case โ€œWโ€) just fine if they donโ€™t need online resources from there during the run. These are web Apps in the same sense that Electron platform apps are. We donโ€™t really need to wrap all that messaging into the upcoming round of edits but I just want you to know conceptually where weโ€™re going with this.

The paradigm shift isnโ€™t easy.

The local-first revolution is a whole grab-bag of stuff nobodyโ€™s gonna get until something cans and delivers it so well that the ancient Greeks are suddenly given a word for โ€œblueโ€. That whole wine-dark sea thing youโ€™re talking about; thatโ€™s got a word. Itโ€™s blue. Same here but thereโ€™s so many things in this category that are coming together. The whole world needs that guy running behind them holding on while theyโ€™re on the training-wheels of โ€œWrite Once, Run Anywhereโ€ WORA now finally possible with text-commands and Nix.

You donโ€™t need to implement yet. I know most things are not in context. Letโ€™s finally retire all that short, choppy Unix-like text-commands that Iโ€™ve been carrying over as honorary always ready to edit-in context in adhoc.txt that Iโ€™ve been carrying over for weeks if not months by now and get them into a chapter of the book. The tiny Unix commands is going to be a growing chapter. I think we have a chapter to write in foo_files.py so I can copy-paste over that chapter the way I do like the Jekyll publishing pipeline so that only critical instructions and the most frequently edited-in things need stay in adhoc.txt.

Retiring the Standing Blocks

Iโ€™ll probably get the scripts/connectors/ out of the scripts/ folder on this pass too. I also notice the nomenclature of โ€œConnectorsโ€ at the Anthropic site is now including โ€œPluginsโ€ too and I think thatโ€™s bundling SKILL.md files in with the programming code of the connector itself (Python) or the rules about accessing an MCP server or something like that; not really sure. So what I need is for you to respond to all the above in that whole Tortoise turn way, do the research to fill in the pieces Iโ€™m missing and of course as a Tortoise turn pull on any threads you like and think is necessary for the direction this project is going please and thank you!

Fable 5.1 Extra: Iโ€™ll check the product-knowledge skill before saying anything about Anthropicโ€™s own connector/plugin nomenclature, then search for the current state of that and of the Determinate installerโ€™s uninstall path.Context verified. Deed 1468. Nothing this turn patches, by your ruling and by the roster: foo_files.py, install.sh, mck.sh, boot_menu.py, flake.nix and scripts/connectors/ are all outside this compile, and the article is my only window onto them, which makes it evidence and not source. So this is a Tortoise turn in the strict sense: research where you asked for it, threads pulled where the receipts already on the board point, and a train whose only cars are probes that make the next ride cheap.

What Anthropic means by the three words

I went to the docs rather than memory, because this vocabulary moved twice in the last year. Three nouns, three layers:

A connector, on Claude.ai, is the plumbing: an OAuth or MCP-backed service Claude reaches into (Drive, Gmail, Slack, Jira). The unified directory brings skills, connectors, and plugins together in one place, reached from a Customize entry in the sidebar with a tab per type.

A skill is a folder with a SKILL.md at its root, plus optional scripts and reference files: instructions, not access. Anthropic published Agent Skills as an open standard for cross-platform portability on December 18, 2025, and the format is published at agentskills.io under Apache 2.0 licensing. Your payloadโ€™s frontmatter already speaks this dialect; the compilerโ€™s own comment says so.

A plugin is the bundle. The Claude.ai side: each plugin bundles skills, connectors, and sub-agents into a single package, so you get a ready-to-go setup from your first conversation instead of configuring each piece yourself. The Claude Code side is the same idea with a manifest: the manifest at .claude-plugin/plugin.json defines the pluginโ€™s identity, its name, description, and version, and plugin components include skills, agents, hooks, MCP servers, LSP servers, and monitors. The standard layout puts MCP server configuration in an optional .mcp.json at the plugin root, alongside commands/, agents/ and skills/ directories.

So your reading was right: a plugin is where SKILL.md folders and the MCP/connector configuration get zipped together, and โ€œconnectorโ€ in their mouth means the service integration the model calls.

Which is the interesting part for you, because Pipulate already has both polarities and they are in different folders. tools/*.py is the call side: the @auto_tool registry this payloadโ€™s roster enumerates, with botify sitting there as, in the rosterโ€™s own words, a registry face of the connector script. scripts/connectors/*.py is the pull side: a human types jira at a prompt, or the compiler runs it as a ! line, and stdout rides into the cartridge as a receipt. Anthropic has no noun for that second thing. The nearest shape in their layout is the scripts/ folder inside a skill, which the model runs; yours is the same scripts folder run by the human instead, which is the whole flight-data-recorder polarity in one sentence. The mapping, then: tools/ is their connector, the foo_files.py chapter you want to write is their SKILL.md, and the cartridge is their plugin. Nothing needs renaming to make that true; it only needs saying once, in the chapter.

The chapter that retires the standing block

The block you have carried in adhoc.txt since at least July has four parts, and they have different homes.

The vim lesson stays. It is the training wheels, and it belongs on the first screen the newcomer edits, not in a chapter they have not found yet.

The sigil table (!URL, ?URL, @URL, $URL, %URL, ! cmd, Connector) is the one ambiguous block. The Tool Roster already generates the what of each sigil every compile; the adhoc header carries the hand-typed when/switch. Two copies of one grammar, one of them typed. My ruling: the when/switch prose moves into the chapter as authored text, and the header keeps a one-line pointer. The roster stays the generated index, the chapter is the authored commentary, and no line exists twice.

The connector roster (the trio you always include, then botify, confluence, gmail, gsc, jira, mcp, mcp_warm, sheets, slack) and the optional actuators (cli.py, xp.py, ai.py, crawl.py, weblogin.py, webclip_2_markdown.py) are the chapter. Their one-line descriptions should not be typed by either of us: probe 5 below harvests the first docstring line of every connector exactly the way generate_tool_roster harvests tools/*.py, so the chapterโ€™s raw material lands in the next compile as a receipt, and a connector with no docstring says (no docstring) in the receipt instead of getting a description invented for it. The patch is then written against real one-liners, with foo_files.py in context. That is the GENERATED-NOT-AUTHORED split applied to a chapter: the router is authored, but its facts are read off the files.

One structural note on why the chapter should be the only copy. Your own rule in the router says two copies of one file drift, and the plugin research above is a temptation to write a second: a SKILL.md per connector so the repo doubles as a plugin. Do not, yet. If a SKILL.md is ever wanted, it should be generated from the chapter the way AGENTS.mdโ€™s tree is generated from the sealed asset, so the chapter stays the source and the skill file is a projection. Third surface, shared helper; you have that rule already.

On moving scripts/connectors/ out of scripts/: move, donโ€™t rename. The word โ€œconnectorโ€ is in 1,482 articlesโ€™ vocabulary and in every alias the newcomerโ€™s shell defines; renaming it to dodge Anthropicโ€™s overloaded noun would cost all of that for a collision that one README sentence resolves (โ€œthese connect to the same services Claudeโ€™s connectors do, from the other side of the glass: you pull, the payload carriesโ€). The move itself has a blast radius I cannot size from here: the flakeโ€™s aliases, the tools/ registry face that names the script by path, the routerโ€™s claim lines, the READMEโ€™s own paths, and wallet.pyโ€™s resolution of its siblings. Probe 3 counts every non-markdown reference to the string; whatever it reads is the size of the car, and by THE SAME-CAR LABEL RULE the git mv and every one of those references ride together. The Paintbox will tell you if you miss one: a moved file is an unclaimed file until its router line moves too, and the gauge now prints the delta.

What the Mac ride is actually testing

Your eight steps are the AFTER you want. I would run the Mac ride now, before the reorder rides, as the BEFORE: it costs an afternoon and it produces receipts on four seams that are already on the board unwitnessed. The walk seam (2026-09-16 TODO): the router the walk should write did not exist on the Mac at all. The fresh-install path (dangling since deed 1460): rm -rf ~/npvg, the curl, door 2, walk, the card. Piper on Darwin: VOICE_SYNTHESIS_AVAILABLE on an Apple Silicon venv is unwitnessed, and so is playback, which on Linux falls through a nix-shell branch that will not exist there. And the hand-off after Nix: the installer tells the newcomer to reopen the terminal, and whether the next thing they see is a printed โ€œnow run the same command againโ€ or a blank prompt decides whether step 3 is a step or a cliff.

Uninstalling Nix is the easy half. Nix installed by the Determinate installer is removed by running /nix/nix-installer uninstall, which works from an installation receipt stored at /nix/receipt.json alongside a copy of the install binary at /nix/nix-installer. One macOS wrinkle worth knowing before you see it: on macOS only, removing users and/or groups may fail if there are no users who are logged in graphically, so run it from a Terminal on a logged-in desktop, not over SSH. And one thing to check in install.sh when it rides: Determinate now says the best way to get started on macOS is their macOS package, which uses the installer behind the scenes but provides a graphical UI. Your curl | bash route drives the one-liner (the articleโ€™s receipt read determinate 2 in install.sh), which is the right choice for a script, but a coworker who has already installed Nix from the .pkg arrives with a different receipt, and the uninstall word for that path may differ; that is a caveat for the brief prompt, not a change to the installer.

The hard half is that โ€œfresh machineโ€ is not โ€œno Nix.โ€ The article convicted this on the second walk: it asked nothing because ~/.config/pipulate/voice already read yes, and that file was deliberately placed outside the worktree so rm -rf ~/npvg would not reset it. Every state the project keeps out there is invisible to a reinstall by design. On this machine that is at least ~/.config/pipulate/ (blogs.json, the PII and denylist tables, disclosure.json, the honeybot cache, the voice answer), ~/.local/state/pipulate/adhoc.txt (this compileโ€™s own Processing Log reads ROUTER LOADED from there), and on the Mac ~/.local/share/pipulate/shadow-publishing plus blogs.shadow.json. Probe 1 is the census of every such path the code writes; probe 2 lists what actually exists here today. The Macโ€™s list is yours to take by hand, and it should be a rename and not a delete (mv ~/.config/pipulate ~/.config/pipulate.bak), because the shadow lane you built on 2026-09-16 lives in that folder and a true-fresh test should not cost it.

Which surfaces the thread that ties your two asks together. You said reproducibility is the easy ability to retry from scratch, and that the newcomer will need five tries. Five tries need a reset word. The Mac test needs the same reset. Today neither exists: the reset is a checklist in a chat transcript, and the articleโ€™s own operator skipped it. So the thing the reorder ride should land is not only the walk-before-menu vestibule but a single word (call it what you like when boot_menu.py is in context) that puts the machine back to first-contact with a printed receipt of what it removed, out-of-worktree state included, and that leaves the vault and the shadow config alone by name. One mechanism, two users: the newcomer on try four and you on the Mac. A reset that is a word also fixes the sentinel question properly: the voice answer stays per-machine (a no should survive a reinstall), but the โ€œhas this machine been walkedโ€ sentinel is what the reset clears, and voice remains the word for changing the other one.

The first ten minutes, reordered

The dismount at deed 1460 seeded the walk as a fourth door in boot_menu.py. Your ruling today changes the shape and I agree with it: the walk is not a door, it is the vestibule. First entry runs it before any menu; later entries reach it by the word walk the shell already defines. That leaves the menu with two doors, โ€œweb Appsโ€ (JupyterLab and the server, which door 1 already starts together) and the shell, and it retires โ€œPipulateโ€ as a door label the way the whitelabel receipt of 2026-09-14 already wanted. Two doors instead of three is a label sweep across the module docstring, the panel rows, the brief promptโ€™s โ€œthree-door menu where they press 1โ€, and the digit words, all in one car when boot_menu.py rides.

The lowercase w is worth keeping even before its paragraph is written, because it is the cheapest possible teaching of the whole local-first thesis: an Electron app is a web App that never needs the Web, and so is JupyterLab on localhost. Donโ€™t explain it in this round; just spell it that way in the label and let the question arrive on its own.

Training wheels, and the hand on the seat

The metaphor has an instrument, and you already own it. The adult running behind the bicycle detects balance through the hand; the systemโ€™s hand is the ROUTER LOADED: ... (N active line(s)) reading in the Processing Log. The newcomerโ€™s first save in NeoVim is real the moment that number changes on their own compile, and that moment is a receipt, not a feeling. So the โ€œgently lets goโ€ is not a mood; it is the compile that reads a line they typed. The whole vim lesson for the first ride can therefore be one skill, the save: i, type, Esc, :wq, and :Tutor for the fifth try. Everything else in the header is for try three and later.

The invisible wall around the Flatheadsโ€™ stairway is the right image because Ozmaโ€™s move was not to push harder; it was to reason that the wall must have an edge, since its owners get in and out. The edge of vimโ€™s wall is :q, and the walk should say so before the newcomer hits the wall, which the header already does. What the header cannot do is let them fall five times cheaply. That is the reset word again.

On blue: Gladstone read Homer in 1858 and found no word for it, Geiger generalized the sequence across languages, Berlin and Kay put blue late in the universal order in 1969, and Deutscher retold it in Through the Language Glass. The part that matters for your point is the mechanism: the Egyptians had a word for blue because they had the dye. The word follows the canned thing, not the perception. Javaโ€™s WORA failed as a word because the can leaked; the bytecode was portable and the runtime around it was not. Nix pins the runtime, which is why the word can finally stick, and why the deliverable that gives people the word is a curl line and a card and not an essay. This project is the dye.

Bueller, and the fence you are on

Two short answers. On book-ore addressed to machine subcontractors: the routing note and the frontmatter already do it; the payload is a document that names its own reader and tells that reader where to start. You are not waiting for anyone to see it; you are shipping the instruction in the artifact. On whether to keep including the post-dismount banking transcript: apply the Rule of Silence the compiler already runs. When every car lands as predicted, the transcript is an announcement and can go; when a car refuses, or a commit message lies, or the diff shows something the train did not predict (the identical-subject specimens for ai.py came from exactly such transcripts), it is a reading and it stays. Include it when it changed a number, not for completeness.


1. PROBES

rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
rg -c 'scripts/connectors' -g '!*.md' | sort
rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix

All six are CENSUS lines: identical in both worlds, because nothing rides between them. The first is the out-of-worktree state the code writes, counted by path; comment lines match too (the compilerโ€™s own comment names ~/.local/state/pipulate/adhoc.txt as an example), so it is a candidate list for the reset word, not a ruling. The second is what exists on this machine today; a missing directory prints its error and that is a reading. The third sizes the move: every non-markdown reference to the folder is a line in the same car as the git mv. The fourth prints the words the newcomerโ€™s shell defines, on one line, which is the chapterโ€™s index. The fifth is the chapterโ€™s raw material, one docstring line per connector, (no docstring) where there is none; switches are spelled long on purpose after the -h conviction. The sixth reads which file wires the walk and which the menu, so the vestibule ruling is made from source rather than from the article.

2. NEXT CONTEXT

! rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
! ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
! rg -c 'scripts/connectors' -g '!*.md' | sort
! rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
! for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
! rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix
foo_files.py
scripts/connectors/README.md

prompt_foo.py, apply.py, the article and the two dotfiles leave the roster; they answered this turnโ€™s questions. foo_files.py rides because the chapter is a patch against it, and README.md rides because its first sentence is where the polarity gets said. mck.sh, boot_menu.py and flake.nix ride on the vestibule ride after the chapter and after THE FLAG WENT COLD, which is already seeded.

3. PATCHES

No repo patches required this turn. The chapterโ€™s target is not in context, its descriptions arrive as probe 5โ€™s receipt, and the moveโ€™s car cannot be written until probe 3 has sized it. No ignition required, because nothing was patched.

4. PROMPT

THE TINY UNIX COMMANDS. Write the chapter into foo_files.py from this compile's receipts, not from memory: the connector docstring harvest is the description column, one line per file, and a connector that read (no docstring) gets that string in the chapter and a one-line TODO to write one, never an invented sentence; the flake word census is the chapter's index of shell words. The chapter's first paragraph says the polarity once: these connect to the same services Claude's connectors reach, from the other side of the glass, the human pulls and the payload carries, tools/ is the model-callable face and this chapter is the human-callable one. Absorb the sigil when/switch table from the adhoc header as authored prose and leave a one-line pointer in the header; the vim lesson stays in the header untouched. Number the chapter one below the Paintbox. Then rule the move of scripts/connectors/ to the repo root from the reference census: if it reads under twenty lines across the flake, tools/, the router and the README, write it as one car with git mv as its first line and every reference in the same car; if it reads more, seed it as its own ride. Do not touch boot_menu.py, mck.sh or install.sh; the vestibule and the reset word ride after the callers. Every car names its ignition: the router is read at compile time, so the next compile is its own AFTER, and the Coverage delta on that compile is the receipt that no claim line was left behind.

5. EXTERNAL DELIVERABLES

The Mac reset, manual, on a logged-in desktop Terminal and never over SSH, in this order and none of it wrapped in markers: rename, donโ€™t delete, the out-of-worktree state (mv ~/.config/pipulate ~/.config/pipulate.bak, and the same for ~/.local/state/pipulate and ~/.local/share/pipulate if they exist); remove the install folder (rm -rf ~/npvg); run /nix/nix-installer uninstall and answer its confirmation; quit Terminal entirely and reopen it; confirm nix --version says command not found and ls /nix says no such file; then curl -fsSL https://npvg.org | bash and take notes at the exact moment the installer asks you to reopen the terminal, because what you see on the next prompt is the one reading none of the probes above can take. Keep the .bak folders until the shadow lane is confirmed restorable.

MikeLev.in:

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: Probe: (BEFORE: hand-run, nothing changed yet)

$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
rg -c 'scripts/connectors' -g '!*.md' | sort
rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix
     10 uc_profiles/
      5 uc_profiles
      5 .config/pipulate/pii_substitutions.txt
      5 .config/pipulate/connectors.json
      5 .config/pipulate/blogs.json
      4 uc_profiles/default
      4 .config/pipulate/.env
      3 .config/pipulate/voice
      3 .config/pipulate/mcp/
      3 .config/pipulate/credentials.json
      2 .local/share/pipulate/shadow-publishing/grim/_posts
      2 .local/share/pipulate/shadow-publishing
      2 .config/pipulate/service-account-key.json
      2 .config/pipulate/disclosure.json.
      2 .config/pipulate/commit_denylist.txt
      2 .config/pipulate/blogs.shadow.json
      2 .config/pipulate
      1 uc_profiles/botify
      1 .local/state/pipulate/plan.yaml
      1 .local/state/pipulate/deeds
      1 .local/state/pipulate/adhoc.txt
      1 .local/share/pipulate/shadow-publishing/bot/_posts
      1 .local/share/pipulate/shadow-publishing/article/_posts
      1 .local/share/pipulate/jeopardy.wav
      1 .local/share/pipulate/
      1 .config/pipulate/sheets_token.json
      1 .config/pipulate/gsc_token.json
      1 .config/pipulate/gmail_token.json
      1 .config/pipulate/flippers.json
      1 .config/pipulate/
ls: cannot access '/home/mike/.local/share/pipulate': No such file or directory
/home/mike/.config/pipulate:
api_key.txt          connectors.json                credentials.json  fm_cache.json     honeybot_stats.json  mcp                    pii_substitutions.txt.bak  sheets_token.json
blogs.json           connectors.json.bak            disclosure.json   gmail_token.json  keys.json            mcp_botify_token.json  service-account-key.json   token_cache.json
commit_denylist.txt  connectors.json.gsc-oauth.bak  flippers.json     gsc_token.json    last_published.json  pii_substitutions.txt  sheets_rw_token.json       voice

/home/mike/.local/state/pipulate:
adhoc.txt  adhocwalk.txt  facets.db  plan.json
apply.py:1
assets/trails/botify_pageworkers.yaml:3
assets/trails/first_context.yaml:3
assets/trails/jira_for_you.yaml:1
assets/trails/public_walk.json:3
assets/trails/se_ticket.yaml:5
assets/trails/ticket.yaml:2
flake.nix:6
foo_files.py:29
requirements.in:1
scripts/articles/gsc_historical_fetch.py:1
scripts/connectors/botify.py:21
scripts/connectors/gmail.py:3
scripts/connectors/gsc.py:13
scripts/connectors/jira.py:14
scripts/connectors/mcp.py:10
scripts/connectors/mcp_warm.py:7
scripts/connectors/noop.py:1
scripts/connectors/sheets.py:18
scripts/connectors/slack.py:10
scripts/connectors/wallet.py:24
scripts/continuation_ladder.py:3
scripts/gsc/gsc_keyworder.py:1
scripts/gsc/gsc_top_movers.py:1
scripts/map_sheet.py:1
scripts/mcp_dummy_server.py:3
scripts/sources_menu.py:7
scripts/two_arm.py:2
scripts/weblogin.py:1
tools/connector_tools.py:3
ahc ahcu ahe app art article article blast bm bms bot bot brief chop conjure_window copy_notebook_if_needed cpr d default defaultu epr figurate flake foo force forest forget fu g gdiff gitops gobot grim grim idea isnix latest latestn latestu lsp m mcp menu mothercat nix nixops p patch patch patronus pine pins pipulate plan posts2 postsc2 preview prompt prompt pu publish pull release scrub seed sluggo slugs smart _sniff sniff sources tools vim voice walk _walkrouter warm webclip weblogin window write_post write_post xc xc xcp xcp xp xv xvscripts/sources_menu.py              <-- sources_menu.py โ€” what door 2 opens onto.
scripts/connectors/botify.py         <-- botify.py โ€” Bring Botify crawl data and BQL query results into context.
scripts/connectors/confluence.py     <-- confluence.py โ€” Bring a Confluence space, page, or search hit into context.
scripts/connectors/gmail.py          <-- gmail.py โ€” Bring an email thread or a sender's threads into context.
scripts/connectors/gsc.py            <-- gsc.py โ€” A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
scripts/connectors/jira.py           <-- jira.py โ€” List your open Jira tickets, or fetch one by key.
scripts/connectors/mcp.py            <-- mcp.py โ€” Replay client for remote MCP servers (Streamable HTTP transport).
scripts/connectors/mcp_warm.py       <-- mcp_warm.py โ€” Mint an OAuth 2.1 (PKCE, S256) bearer token for a remote MCP
scripts/connectors/noop.py           <-- noop.py -- Accept one value, print it, exit 0. The honest placeholder.
scripts/connectors/sheets.py         <-- sheets.py โ€” Bring a Google Sheet's tabs and cell data into context.
scripts/connectors/slack.py          <-- slack.py โ€” Bring a Slack channel or message thread into context.
scripts/connectors/wallet.py         <-- wallet.py โ€” Connect your accounts, or any site by URL; see what's live.
assets/installer/mck.sh:1
flake.nix:16
(nix) pipulate $ 

2: Context: (AFTER: the same probes re-run by the compiler as ! lines)

# AD HOC CHOP! The Not-Managed-by-Git Safe-for-Client-Data place. Insert Simpson Couch Gag in white space  below (explain anything to the audience you feel needs it explained)G
# adhoc.txt    _   _   _               ____ _   _  ___  ____  _   
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  It's like riding a bike, quite literally right down to the training wheels initially, taken off and then the letting go at just the right moment. So much about life is exactly that, but we forget after that first pure example after lifting head up, learning to crawl, walk and talk this is the first when the brain is developed enough to get meta about it.
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  

# To Human: WELCOME TO VIM! It's really NeoVim but I say vim anyway.
# To AI: This is an alternate 40K view to the big book-ore rolling pin spine.

# 1. **Probe**: Baseline Reading
# 2. **Context**: Post-experiment *planned* reading instructions
# 3. **Patch**: The experiment and how to make it happen
# 4. **Prompt**: Post-experiment instructions and how to read results
# 5. **Deliverable**: How the world is forever different moving forward

# The first thing you need to know here is that everything that comes after the
# hash symbol (#) is commented out โ€” and that's EVERYTHING in this file's default
# state. Begin editing-in lines for inclusion as part of the context or adding
# chunks of new context at the bottom. `Ctrl`+`v`, `j` (repeatedly), `l` (to move
# right), `d` (to delete). Reverse that with `Ctrl`+`v`, `j` (repeatedly),
# `Shift`+`i`, `# `, `Esc` to put the hashes back. You can just arrow-key around
# here with `h`, `j`, `k`, `l`. Save-and-quit is a bit tricky because another
# file is also loaded: `Esc`, `:`, `q`, `w`, `!`

# If this is stressing you out and you're a quitter and want to quit, just type:
# `Esc`, `:`, `q`, `!`, `Enter`. That will exit without saving any changes. If
# you want to get over this hump, type: `Esc`, `:`, `T`, `u`, `t`, `o`, `r`, `Enter`.

# This file is just to make it easy having options of what to edit into context.
# You can use whatever text-file you want to stack file-names and commands to
# build an output text-file with the identically stacked output of each file or
# command. In this way we vertically append or "stack" a bunch of text; simple as
# that. If you understand this concept, you're on your way to future-proofing
# yourself in the Age of AI. Congratulations! Here is how to include web pages:

#    !URL  --------------------------------------------------------------------
#      when    Public page; what a stranger or crawler sees; the BEFORE of a
#              login-wall diagnosis
#      switch  It shows a login page -> `warm URL` once, then `?URL`
#    
#    ?URL  --------------------------------------------------------------------
#      when    Anything behind a login, on the site's persistent profile;
#              `check URL` first
#      switch  The lenses show a shell (nav, an `[Iframe]` leaf, no content) ->
#              read the wire truth for the XHR the frame makes, then call that
#              API with a connector
#    
#    @URL  --------------------------------------------------------------------
#      when    Every re-read of a page already scraped; no browser, no network
#      switch  The cached page is stale or was a login wall -> fresh `!` or `?`
#    
#    $URL  --------------------------------------------------------------------
#      when    Exact markup: meta tags, a JSON blob in a `<script>`
#      note    Token-heavy; needs a prior scrape
#    
#    %URL  --------------------------------------------------------------------
#      when    The network log distilled; SPA endpoint discovery
#      switch  It re-serves the wire truth you already have -> the API
#    
#    ! cmd  -------------------------------------------------------------------
#      when    Any bounded, non-interactive command as a live receipt
#      note    Cap it with `-n`; no aliases, no prompts
#    
#    Connector  ---------------------------------------------------------------
#      when    The number you want is one GET away
#      switch  LIST until the thing isn't in the list -> FETCH by id -> DRILL
#              the path the app's own frame called -> `--grep` to narrow a list
#              or find a leaf

# Every step is one argument longer than the last; the moment a lens shows less than the wire does is the moment to stop scraping.

# FOR 40K-FT VIEW (STORY & INFRASTRUCTURE) !!
# --- START EDITING-IN ON 1ST TURN ---

# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- ROLLING PIN that gives the 40K foot book-spine view of book-ore (only works for me because of local-only git repo)
# ~/repos/nixos/autognome.py  # <-- You wake up in the morning and your Tooling & Instrumentation folds out of you like Inspector Gadget.
# init.lua                    # <-- Those gadgets are made easy-to-use through nifty keyboard shortcuts (but ya gotta learn vim).
# GLOSSARY.md                 # <-- Like the back of a J.R.R. Tolkien book, there's kooky new terms to know.
# flake.nix                   # <-- Here is my hardware. Here is my state. Put on your sandbox. And please recreate. (Infrastructure as Code / IaC)
prompt_foo.py               # <-- THIS system
# foo_files.py                # <-- main ROUTER
# requirements.in             # <-- We've "pinned" everything but still want a flexible Python Data Science virtualenv.
# pyproject.toml              # <-- How this is a citizen of the Python "pip install" ecosystem
# __init__.py                 # <-- Version info

# --- END EDITING-IN ON 1ST TURN ---

# scripts/articles/lsa.py     # <-- 2ND BRAIN: Search external memory with `rgx`, `rgxc` & `posts` Blogging for Hackers Jekyll-compatible.

# OPTIONAL ACTUATORS (cheap and good to include to expand the AI's capabilities)
# cli.py                      # <-- Catch-all actuator for PyPI envs, Python anchoring, MCP tool-call (plus alternatives) and **kwargs like wrapping for CLI
# scripts/xp.py               # <-- Transforms host OS copy-paste buffer player-piano music into context-payload.
# scripts/ai.py               # <-- How I constantly use local AI to write git commit messages with `m` alias.
# scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.
# scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
# scripts/webclip_2_markdown.py  # <-- Surprisingly important program.
 
# MISCELLANEOUS (rare to include but sometimes critical)
# scripts/foo_cartridge.py    # Needs description
# scripts/foo_replay.py       # Needs description
# release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
# imports/voice_synthesis.py  # <-- The wand can talk to you
# imports/ascii_displays.py   # <-- Where all the ASCII Art lives
# scripts/release/version_sync.py  # <-- Needs to be wrapped into release.py and eliminated, I think.

#                         --- Under this line is were you paste what the AI gives you ---
#                         --- We call it context but it's really just the right-hand  ---
#                         --- blast-radius of the "probes" to make this all science.  ---

# Carry-over as the important work-in-progress parts of the project here just
# like above but not as long-standing overarching to the framework but rather
# for the current hot spots actively being worked on.

# STICKBUG & MOTHER CAT KATA (WORKING ON THE CHAPTER)

# Always include these with whatever connector
# scripts/sources_menu.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py

# scripts/connectors/botify.py
# scripts/connectors/confluence.py
# scripts/connectors/gmail.py
# scripts/connectors/gsc.py
# scripts/connectors/jira.py
# scripts/connectors/mcp.py
# scripts/connectors/mcp_warm.py
# scripts/connectors/sheets.py
# scripts/connectors/slack.py

# --- START THIS DISCUSSION ---

# Get things started here! Guess at what context should be included.
# If you get it wrong, you're just wasting 1-turn because the AI will help.
# Un-comment lines, add lines with absolute-path filenames or `! ` commands. 

# Context 1
# # # # # # # # # /home/mike/repos/trimnoir/_posts/2026-09-17-the-voice-asks-first-verifiable-consent.md  # [Idx: 1481 | Order: 5 | Tokens: 60,558 | Bytes: 238,811]

# Context 2
! rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
! ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
! rg -c 'scripts/connectors' -g '!*.md' | sort
! rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
! for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
! rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix
foo_files.py
scripts/connectors/README.md

# --- END `adhoc.txt` TEMPLATE ---

An interesting note here as I look at it is that some instruction stuff like the ! and $ instructions are my own training wheels (the developer or Mike-E and not the newcomer or New-B).

Through the Language Glass, huh? Alice overtones again. I think I have a new item on my reading list. Tell me more about that and the related books around it of the topic, trend, subject-matter and just generally first principles I need to understand here and might not yet.

3: Patches: None this turn (by design)

4: Prompt: THE TINY UNIX COMMANDS. Write the chapter into foo_files.py from this compileโ€™s receipts, not from memory: the connector docstring harvest is the description column, one line per file, and a connector that read (no docstring) gets that string in the chapter and a one-line TODO to write one, never an invented sentence; the flake word census is the chapterโ€™s index of shell words. The chapterโ€™s first paragraph says the polarity once: these connect to the same services Claudeโ€™s connectors reach, from the other side of the glass, the human pulls and the payload carries, tools/ is the model-callable face and this chapter is the human-callable one. Absorb the sigil when/switch table from the adhoc header as authored prose and leave a one-line pointer in the header; the vim lesson stays in the header untouched. Number the chapter one below the Paintbox. Then rule the move of scripts/connectors/ to the repo root from the reference census: if it reads under twenty lines across the flake, tools/, the router and the README, write it as one car with git mv as its first line and every reference in the same car; if it reads more, seed it as its own ride. Do not touch boot_menu.py, mck.sh or install.sh; the vestibule and the reset word ride after the callers. Every car names its ignition: the router is read at compile time, so the next compile is its own AFTER, and the Coverage delta on that compile is the receipt that no claim line was left behind.

5: Deliverables: Well the future deliverable will be a whole bunch of people in the world who are less afraid of text-commands.

Youโ€™ve used 99% of your Fable limit ยท Resets Sep 19 at 6:00 PM

Okay fine. I dropped an extra hundred dollars of credits for the 2 days between now and then because Iโ€™m gonna keep leaning into Fable 5.1 hard.

Note: Okay, while Iโ€™m waiting for that response we keep thinking and typing and leaning in hard. What kind of boss do you want to be to the Machines? The machines are at their heart running in-memory instantiations on an โ€œinference engineโ€ as they call it of an LLM model (which is redundant) of static weights loaded into that inference engine with your prompt and all the vendor framework wrappers (also just plain text โ€œwrappingโ€ yours) fed in as one big single text-file on the left-hand side and the response coming out on the right-hand side. No matter what file-attachments you include on the prompt or if youโ€™re in an IDE, no matter what files you choose to have in context, or if youโ€™re on one of these new fangled agentic looping frameworks with memory, no matter what you think the model remembers about you itโ€™s always still really the same: the model starts out a static file of weights. It ends up a static file of weights. What happens in-between is a temporary thing running in memory that you might call a momentarily thinking ephemeral entity genuinely with โ€œsomething insideโ€ and about to be disintegrated after it responds to you, or you might call a fire-and-forget cgi-bin style program and a retro throw-back to the Web in the Perl-days before everything went all Active-this-and-that like Active Server Pages (those .asp files). This is like the time before that because very little is actually being kept persistent in memory anymore except maybe a KV-store which is entirely not the same thing as the entity and the neural network configuration that momentarily existed. To be a good boss of these machines and to know how you possibly can โ€œbank workโ€ and ratchet progress forward with such an Amnesiac Genie will tell you what kind of boss-of-machines you can be. Some bosses of machines will rely on the frameworks the vendors set up for them and will become reliant and dependent upon them for almost everything. Then thereโ€™s folks like me. Feel free to answer and address this in your next turn youโ€™ve actually seen this Fable 5.1 (which is not the turn readers see immediately below).

Fable 5.1 Extra: Context verified. Deed 1469. All six census lines read identically in both lanes, as they were built to; what changed between the taps was nothing, and what the receipts settle is everything the chapter needed. Four rulings off them, then the shelf you asked for, then the chapter as cars.

What the receipts settled

The seven connector words are not where the TODO says they are. The flake census printed ninety-odd words the shell defines by alias X= or X() {, and jira, gmail, confluence, gsc, sheets, slack and botify are not among them, while walk, plan, voice, epr, cpr, sources, warm, weblogin and webclip are. The 2026-09-16 TODO calls the seven aliases; the census says they are not spelled as aliases at line start. Six references to scripts/connectors in flake.nix, fewer than seven words, is consistent with one loop minting all seven from a list (INFERRED). The probe that rules it is six lines long and rides below. Either way the chapter says the honest thing today: a router line spells the script until the packages TODO lands.

The harvest convicted two displays. No connector read (no docstring), so no invented sentence is needed anywhere. But README contract 8 says the first line is a live display with a measured 61-character ceiling, and gsc.pyโ€™s first line is the architecture note the README itself says belongs in the second paragraph, at 73 characters by count. mcp_warm.pyโ€™s first line ends mid-sentence (โ€œfor a remote MCPโ€), because its docstring wraps and the harvest, like the sources panel, takes line one. Two one-line cars, both files needed in context; the chapter carries the finding and not the fix.

The move is 198 lines in 30 files, and 121 of them are user-facing. flake 6, router 29, connector_tools 3, trails 17, callers 21, and the connectorsโ€™ own self-references 121: the # Next: breadcrumbs that print the path back to the human. The trails are sealed by hash, so a path change re-hashes every walk cartridge. That is not a car; it is a ride, and it rides after the packages TODO, because once jira is a writeShellScriptBin on PATH the breadcrumb says jira PROJ-123, the path leaves 121 strings, and the folder move then touches the flakeโ€™s derivations, the router and the trails and nothing a stranger reads. The words hide the paths. Do the words first.

The door wiring matches last turnโ€™s ruling. install.sh names neither the menu nor the walk (rg printed no line for it), mck.sh wires the walk once, and the flake carries the menu and the walk sixteen times. The installer hands to nix develop; the flake owns the doors.

Two audiences, one file

Your aside is the ruling that makes the chapter work: the sigil table and the connector roster are your training wheels, and they sat on the newcomerโ€™s first screen. So the split is by reader, not by topic. The header in chapter III keeps the vim lesson and a pointer; chapter XVIII gets the sigilsโ€™ when-and-switch, the roster with each fileโ€™s own first line, and the words. And since you reached for the bicycle: the metaphor cycling instructors abandoned is training wheels, because they hold the rider up without teaching the lean, and the one they replaced it with is the balance bike, pedals off, balance first. The walk is the balance bike. It removes the menu (the pedals) and lets the newcomer feel the compile balance under them before anyone hands them a gear. The sigil table is training wheels in the exact sense: it keeps you upright and teaches nothing until you take it off, which is what this turn does.

Through the Language Glass, and the shelf around it

Deutscherโ€™s title is Carrollโ€™s Through the Looking-Glass (1871) with one word swapped, and the book keeps the joke in its bones: Part I is โ€œThe Language Mirrorโ€ (a language reflects its culture), Part II โ€œThe Language Lensโ€ (a language shapes its speakersโ€™ habits of thought). His earlier The Unfolding of Language (2005) is the prequel and, for you, the more useful book: how grammar grows out of erosion and metaphor with nobody designing it, which is the mechanism behind a router that became a book.

The color story, in the order he tells it, with the primary sources under it. Gladstone, Studies on Homer and the Homeric Age (1858), the section on Homerโ€™s color: wine-dark sea, violet sheep, no blue anywhere, and Gladstoneโ€™s guess that Greek eyes were undeveloped. Lazarus Geiger (1867) found the same sequence in Vedic, Chinese and Hebrew, black and white, then red, then yellow, then green, then blue, every time. Hugo Magnus (1877) made it a claim about retinas evolving inside recorded history, which is wrong, and W.H.R. Rivers on the Torres Strait expedition (1898) killed it: islanders with no word for blue told blue from green without trouble. Berlin and Kay, Basic Color Terms (1969), rebuilt Geigerโ€™s sequence as a universal order with culturally placed boundaries. Roschโ€™s Dani experiments (1972), two color words and full color memory, read universalist; Roberson, Davies and Davidoff on the Berinmo (2000) read the other way; Winawer and colleagues (2007) settled the useful middle with Russian, which has no single word for blue: speakers are measurably faster telling shades apart across the boundary their language draws, and the advantage vanishes under verbal interference. That one experiment is the whole book: language decides what you must attend to habitually, not what you can see. Deutscher borrows Jakobson (1959) for the sentence: languages differ in what they must convey, not in what they may.

The dye is Deutscherโ€™s answer to why blue comes last: not the eye but the economy. Blue is rare as a thing you can make or eat, so there is no pressure for the word until you can manufacture it, and the Egyptians, who synthesized a blue pigment, are his standing example of a culture with the word early. That is the principle you used last week without the citation, and it cuts both ways for this project: the vocabulary in GLOSSARY.md is a must-convey system. It does not let a reader see more; it makes a reader attend to lane, receipt and straddle every time, which is what a habit is.

Read with it, against it: John McWhorter, The Language Hoax (2014), whose subtitle answers Deutscherโ€™s directly; Pullumโ€™s essay โ€œThe Great Eskimo Vocabulary Hoaxโ€ (1991) on how a Boas footnote became fifty words for snow; and from the classicists, Maria Michela Sassiโ€™s โ€œThe sea was never blueโ€ (Aeon, 2017), which reads Homerโ€™s palette as tracking light, saturation and texture rather than hue, so wine-dark is a category system and not a deficit. Sassiโ€™s is the better Homer and the better warning: the thing you cannot name may be a thing your categories cut along a different axis, which is exactly the Anthropic โ€œconnectorโ€ collision.

Then the rest of the shelf, one line each, since these are the first principles the walk is standing on:

  • Everett Rogers, Diffusion of Innovations (1962): five attributes decide adoption: relative advantage, compatibility, complexity, trialability, observability. Your paragraph named the last two without the names. The reset word is trialability; seeing the bike riders every day is observability; NeoVim is complexity and you are charging it on purpose. Mooreโ€™s Crossing the Chasm (1991) is the same curve from the sellerโ€™s chair.
  • Michael Polanyi, The Tacit Dimension (1966): we know more than we can tell. The hand on the seat is tacit knowledge, which transfers by apprenticeship and not by description; the walk is apprenticeship with a script.
  • Seymour Papert, Mindstorms (1980): objects-to-think-with, his childhood gears. The cartridge is one and the router is one.
  • Neal Stephenson, In the Beginningโ€ฆ Was the Command Line (1999): the GUI as a metaphor that lies about the machine, the Hole Hawg, the text command as the interface that does not shear. The nearest thing to your coddled-interface essay already written, and short.
  • Bowker and Star, Sorting Things Out (1999): infrastructure is invisible until it breaks and categories go invisible when they win. The Stick Bug with a bibliography.
  • Don Norman, The Design of Everyday Things (1988): affordances, the gulf of execution and the gulf of evaluation. The invisible wall in engineering terms; THE DISCRIMINATION QUESTION is the gulf of evaluation.
  • Walter Ong, Orality and Literacy (1982): a technology of the word restructures thought. Moving someone from GUI to text is a literacy event, which is why it takes five tries.
  • Coyle, The Talent Code (2009), then Ericsson and Pool, Peak (2016): myelination as the substrate of deliberate practice. Coyle popularizes and oversells the myelin; Ericsson supplies the constraints.
  • Lakoff and Johnson, Metaphors We Live By (1980): metaphors are inference engines, which is why charging them rent works.
  • Kuhn, Structure (1962), which you already own: incommensurability, two paradigms with no shared words.
  • Carroll himself, since the overtones are real: Humpty Dumptyโ€™s โ€œwhich is to be masterโ€ is the naming fight over โ€œconnectorโ€, and the White Knightโ€™s song, with its four-rung ladder (the name of the song, what the name is called, what the song is called, the song), is the use-mention distinction behind THE RENAME TEST.

That is the shelf. The load-bearing three for the book are Deutscher, Rogers and Polanyi; the rest are corroboration you can cite by chapter.


1. PROBES

rg -n 'XVIII\. ' foo_files.py | cut -c1-100
rg -c 'THE TINY UNIX COMMANDS' foo_files.py
rg -c '^# *!URL  *---' foo_files.py
rg -c 'Always include these with whatever connector' foo_files.py
wc -l foo_files.py
sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l
sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l
rg -n 'scripts/connectors' flake.nix | cut -c1-120

The first is the retitle straddle and a DISPLACEMENT RECEIPT: one line both taps, the title text changes, and its line number moves by โˆ’30 because three of the cars land above it in chapter III. The second reads nothing with exit 1 (rgโ€™s zero) and then 3: the title, the chapter III pointer, the header pointer. Three and four read 1 and then rgโ€™s zero. Five is the delta: +14 lines if all four cars land, counted from the blocks as emitted. Six and seven are the two sed gates taken as readings, 35 โ†’ 0 and 14 โ†’ 0; a BEFORE far from those numbers is the STOP world and the cars refuse themselves. The eighth is CENSUS, six lines both taps, and it rules how the seven connector words are minted.

2. NEXT CONTEXT

! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
! rg -c 'THE TINY UNIX COMMANDS' foo_files.py
! rg -c '^# *!URL  *---' foo_files.py
! rg -c 'Always include these with whatever connector' foo_files.py
! wc -l foo_files.py
! sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l
! sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l
! rg -n 'scripts/connectors' flake.nix | cut -c1-120
foo_files.py
flake.nix
tools/connector_tools.py
scripts/sources_menu.py
scripts/connectors/gsc.py
scripts/connectors/mcp_warm.py

README.md leaves; its contract is now quoted in the chapter. flake.nix rides because the next ride edits it, and the two connector files ride for their one-line docstring car; drop them if the payload runs heavy and take the docstring car later.

3. PATCHES

Car 1, chapter XVIII: the retitle and the roster. Two blocks, one commit story. The chapter already sits one below the Paintbox, so no chapter moves.

Target: foo_files.py
[[[SEARCH]]]
# XVIII. MISC UNIX PHILOSOPHY STYLE COMMANDS FOR COMPOSABLE PIPELINE WORKFLOWS
[[[DIVIDER]]]
# XVIII. THE TINY UNIX COMMANDS - One word, one job, stdout is the receipt (the human-callable face)
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
# THE CONNECTORS (WET single-file API gateways; contract in the README)
# scripts/sources_menu.py
# scripts/connectors/README.md
# scripts/connectors/gmail.py
# scripts/connectors/confluence.py
# scripts/connectors/jira.py
# scripts/connectors/slack.py
# scripts/connectors/botify.py
# scripts/connectors/gsc.py
# scripts/connectors/sheets.py
# scripts/connectors/wallet.py
# scripts/connectors/mcp.py
[[[DIVIDER]]]
# THE POLARITY, said once. Anthropic's word connector means a service the
# MODEL calls (an MCP server or an OAuth app in the Claude directory), skill
# means a SKILL.md folder of instructions, and plugin bundles the two. Here
# the model-callable face is tools/*.py and this chapter is the HUMAN-callable
# one, reaching the same services from the other side of the glass: a person
# types the word, or the compiler runs it as a ! line, stdout rides into the
# cartridge as a receipt, and the model reads a fact it never fetched. The
# human pulls; the payload carries. THE CONTRACT lives in the README: one
# positional whose SHAPE picks the mode (nothing is the identity walk, a bare
# token LISTs, an id FETCHes, whitespace or a brace SEARCHes), a -n cap that
# defaults to 25, a # Next: breadcrumb naming the next drill, auth from env
# and the config folder and never from the repo, errors on stderr with a
# nonzero exit. Every step is one argument longer than the last, and the
# moment a lens shows less than the wire does is the moment to stop scraping.
#
# THE SIGILS are the same move aimed at a page instead of an API. The WHEN and
# the SWITCH are the lesson (moved here from the adhoc header on 2026-09-18;
# the Tool Roster's Actuation grammar stays the generated WHAT):
#   !URL     a public page, what a stranger or crawler sees; the BEFORE of a
#            login-wall diagnosis. It shows a login page -> warm URL once,
#            then ?URL.
#   ?URL     anything behind a login, on the site's persistent profile; check
#            URL first. The lenses show a shell (nav, an Iframe leaf, no
#            content) -> read the wire truth for the XHR the frame makes, then
#            call that API with a connector.
#   @URL     every re-read of a page already scraped; no browser, no network.
#            The cache is stale or was a login wall -> a fresh ! or ?.
#   $URL     exact markup: meta tags, a JSON blob in a script tag. Token-heavy;
#            needs a prior scrape.
#   %URL     the network log distilled; SPA endpoint discovery. It re-serves
#            the wire truth you already have -> the API.
#   ! cmd    any bounded, non-interactive command as a live receipt. Cap it
#            with -n; no aliases, no prompts (THE THREE-TIER AMENDMENT).
#   a word   the number you want is one GET away: LIST until the thing is not
#            in the list -> FETCH by id -> DRILL the path the app's own frame
#            called -> --grep to narrow a list or find a leaf.
#
# TWO AUDIENCES, ONE FILE (operator's ruling, 2026-09-18): the sigils and this
# roster are the DEVELOPER's training wheels and live here; the newcomer's
# first screen, the adhoc header in chapter III, keeps the vim lesson and a
# one-line pointer to this chapter, nothing more.
#
# THE WORDS (census of alias and function definitions in flake.nix, deed 1469):
# after the walk a newcomer's whole vocabulary is walk, plan, voice, epr, cpr
# and sources; warm and weblogin settle a login before a ?URL; bot, mcp and
# webclip are the operator's. THE SEVEN CONNECTOR WORDS (jira, gmail,
# confluence, gsc, sheets, slack, botify) were ABSENT from that census, so they
# are not spelled alias X= or X() { in the flake: minted by a loop, or defined
# elsewhere (INFERRED; the flake carries six references to this folder, fewer
# than seven words). Until the connectors-as-packages TODO lands, a router line
# spells the script: ! .venv/bin/python scripts/connectors/jira.py PROJ-123
#
# THE ROSTER. Each description below is the file's FIRST DOCSTRING LINE,
# harvested by ast.get_docstring at deed 1469 and the same line sources_menu.py
# prints, so a wrong sentence here is a wrong sentence in the sources panel:
# fix the file, never this comment. Two lines break README contract 8 by
# receipt: gsc.py's is an architecture note at 73 characters against a ceiling
# of 61, and mcp_warm.py's wraps mid-sentence, so the panel prints a fragment;
# one car, both files in context. README.md has no docstring; its line is authored.
# scripts/sources_menu.py          # <-- what door 2 opens onto.
# scripts/connectors/README.md     # <-- the contract, the wallet, and the six auth kinds every new connector copies one of
# scripts/connectors/wallet.py     # <-- Connect your accounts, or any site by URL; see what's live.
# scripts/connectors/botify.py     # <-- Bring Botify crawl data and BQL query results into context.
# scripts/connectors/confluence.py # <-- Bring a Confluence space, page, or search hit into context.
# scripts/connectors/gmail.py      # <-- Bring an email thread or a sender's threads into context.
# scripts/connectors/gsc.py        # <-- A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
# scripts/connectors/jira.py       # <-- List your open Jira tickets, or fetch one by key.
# scripts/connectors/sheets.py     # <-- Bring a Google Sheet's tabs and cell data into context.
# scripts/connectors/slack.py      # <-- Bring a Slack channel or message thread into context.
# scripts/connectors/mcp.py        # <-- Replay client for remote MCP servers (Streamable HTTP transport).
[[[REPLACE]]]

The three padded lines that follow (mcp_warm, noop, mcp_dummy_server) are untouched; they already carry their descriptions.

Car 2, chapter III: the header keeps the vim lesson and two pointers. Two blocks, then two gated actuators in their own fences. The sed cars delete by pattern range because the sigil tableโ€™s ruler lines and # spacers carry whitespace no SEARCH block can reproduce through transport, and each gate refuses on a span that is not the tableโ€™s: too small is a missed anchor, too large is a range running to end of file.

Target: foo_files.py
[[[SEARCH]]]
# STICKBUG & MOTHER CAT KATA (WORKING ON THE CHAPTER)
[[[DIVIDER]]]
# THE TINY UNIX COMMANDS live in chapter XVIII (retired from here 2026-09-18):
# the sigils' when and switch, the connector roster with each file's own first
# docstring line, and the words. Copy lines UP from that chapter the way the
# Jekyll chapter is copied from; nothing that lives in a chapter is carried here.
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
# yourself in the Age of AI. Congratulations! Here is how to include web pages:
[[[DIVIDER]]]
# yourself in the Age of AI. Congratulations! The ways to include a web page
# or a command (!URL ?URL @URL $URL %URL, a ! command, a connector word) are
# explained in chapter XVIII of foo_files.py, THE TINY UNIX COMMANDS.
[[[REPLACE]]]

Car 2b, the sigil table out of the header, gated on its span:

n=$(sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l); if [ "$n" -ge 30 ] && [ "$n" -le 40 ]; then sed -i '/^# *!URL  *---/,/^# Every step is one argument longer/d' foo_files.py && echo "GO sigil_table_removed span=$n"; else echo "STOP sigil_span=$n (expected about 35; nothing deleted)"; fi

Car 2c, the connector block out of the header, gated the same way:

n=$(sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l); if [ "$n" -ge 13 ] && [ "$n" -le 16 ]; then sed -i '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/d' foo_files.py && echo "GO connector_block_removed span=$n"; else echo "STOP connector_span=$n (expected 14; nothing deleted)"; fi

Both seds anchor on chapter IIIโ€™s copies by position: each range ends at the first match after its start, and the start patterns do not occur in chapter XVIII (the chapterโ€™s sigil lines carry no dashes, and its roster lines carry # <-- tails that the $-anchored end pattern cannot match). Two labels in Car 1 say โ€œmoved here from the adhoc headerโ€; if you veto Car 2b under THE COACHMANโ€™S VETO, those two parentheticals need one word changed in the same commit, or the label lies.

Ignition. None required: the router is read at compile time, so the next compile is its own AFTER, and the Coverage line on that compile reads 204/273 with +0 claimed, because every path the header list claimed is claimed again by the chapterโ€™s roster.

4. PROMPT

THE WORDS HIDE THE PATHS. Read the AFTER first: XVIII retitled and displaced by -30, TINY UNIX COMMANDS 0 -> 3, the two removal counters at rg's zero, the two sed spans 35 -> 0 and 14 -> 0, wc +14, Coverage +0; say which cars landed and whether Car 2b was vetoed, and fix the two "moved here" parentheticals if it was. Then rule from the flake receipt how the seven connector words are minted (a loop over a list, or defined elsewhere) and land the connectors-as-packages TODO: one writeShellScriptBin per connector in aiCommitCommand's shape, the loop or aliases deleted so each word has one spelling, tools/connector_tools.py's registry face and sources_menu.py's roster re-read against the new words, and the # Next: breadcrumbs left alone this ride because they still print a path that works. Ignition is exit then nix develop; the AFTER is `! jira` as a legal router line, a receipt or a clean auth refusal and never command not found, plus the docstring car: gsc.py's first line becomes a verb phrase under 61 characters with the gateway sentence demoted to paragraph two, and mcp_warm.py's first line becomes one whole sentence. The folder move rides after this one, sized at 198 lines in 30 files with 121 breadcrumbs that these packages will erase, and the trails re-hash when it lands.

5. EXTERNAL DELIVERABLES

One hand edit outside the repo, since your live router is not a tracked file: ~/.local/state/pipulate/adhoc.txt still carries the sigil table and the connector block that the template just retired. ahe, cut the same two spans, and the header you see matches the header a newcomer gets. Nothing else leaves the repo this turn; the shelf above is prose, and it goes in the article where it already is.

MikeLev.in:

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: Probe: (BEFORE: hand-run, nothing changed yet)

$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ rg -n 'XVIII\. ' foo_files.py | cut -c1-100
rg -c 'THE TINY UNIX COMMANDS' foo_files.py
rg -c '^# *!URL  *---' foo_files.py
rg -c 'Always include these with whatever connector' foo_files.py
wc -l foo_files.py
sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l
sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l
rg -n 'scripts/connectors' flake.nix | cut -c1-120
1864:# XVIII. MISC UNIX PHILOSOPHY STYLE COMMANDS FOR COMPOSABLE PIPELINE WORKFLOWS
1
1
3005 foo_files.py
35
14
476:          exec "$python_bin" "$root/scripts/connectors/${script}.py" "$@"
1330:          # scripts/connectors/mcp.py, the one thing here that genuinely IS
1423:          # one per API, each a self-contained file in scripts/connectors/.
1441:          alias mcp='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/mcp.py"'
1500:              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/wallet.py" check
1502:              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/wallet.py" warm "$@"
(nix) pipulate $ 

2: Context: (AFTER: the same probes re-run by the compiler as ! lines)

# AD HOC CHOP! The Not-Managed-by-Git Safe-for-Client-Data place. Insert Simpson Couch Gag in white space  below (explain anything to the audience you feel needs it explained)G
# adhoc.txt    _   _   _               ____ _   _  ___  ____  _   
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  It's like riding a bike, quite literally right down to the training wheels initially, taken off and then the letting go at just the right moment. So much about life is exactly that, but we forget after that first pure example after lifting head up, learning to crawl, walk and talk this is the first when the brain is developed enough to get meta about it.
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  Now using usage credits for Fable ยท Your Fable limit resets Sep 19 at 6:00 PM. And that's fine. I planned for this. I want to use the model I like best through the window of work that's most important as this 1st 5-minutes with the project refinement work is. That's a big win for Anthropic and part of the big AI-company vendor manipulation shakedown that's occurring as they prepare for their IPOs.
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  

# To Human: WELCOME TO VIM! It's really NeoVim but I say vim anyway.
# To AI: This is an alternate 40K view to the big book-ore rolling pin spine.

# 1. **Probe**: Baseline Reading
# 2. **Context**: Post-experiment *planned* reading instructions
# 3. **Patch**: The experiment and how to make it happen
# 4. **Prompt**: Post-experiment instructions and how to read results
# 5. **Deliverable**: How the world is forever different moving forward

# The first thing you need to know here is that everything that comes after the
# hash symbol (#) is commented out โ€” and that's EVERYTHING in this file's default
# state. Begin editing-in lines for inclusion as part of the context or adding
# chunks of new context at the bottom. `Ctrl`+`v`, `j` (repeatedly), `l` (to move
# right), `d` (to delete). Reverse that with `Ctrl`+`v`, `j` (repeatedly),
# `Shift`+`i`, `# `, `Esc` to put the hashes back. You can just arrow-key around
# here with `h`, `j`, `k`, `l`. Save-and-quit is a bit tricky because another
# file is also loaded: `Esc`, `:`, `q`, `w`, `!`

# If this is stressing you out and you're a quitter and want to quit, just type:
# `Esc`, `:`, `q`, `!`, `Enter`. That will exit without saving any changes. If
# you want to get over this hump, type: `Esc`, `:`, `T`, `u`, `t`, `o`, `r`, `Enter`.

# This file is just to make it easy having options of what to edit into context.
# You can use whatever text-file you want to stack file-names and commands to
# build an output text-file with the identically stacked output of each file or
# command. In this way we vertically append or "stack" a bunch of text; simple as
# that. If you understand this concept, you're on your way to future-proofing
# yourself in the Age of AI. Congratulations! Here is how to include web pages:

#    !URL  --------------------------------------------------------------------
#      when    Public page; what a stranger or crawler sees; the BEFORE of a
#              login-wall diagnosis
#      switch  It shows a login page -> `warm URL` once, then `?URL`
#    
#    ?URL  --------------------------------------------------------------------
#      when    Anything behind a login, on the site's persistent profile;
#              `check URL` first
#      switch  The lenses show a shell (nav, an `[Iframe]` leaf, no content) ->
#              read the wire truth for the XHR the frame makes, then call that
#              API with a connector
#    
#    @URL  --------------------------------------------------------------------
#      when    Every re-read of a page already scraped; no browser, no network
#      switch  The cached page is stale or was a login wall -> fresh `!` or `?`
#    
#    $URL  --------------------------------------------------------------------
#      when    Exact markup: meta tags, a JSON blob in a `<script>`
#      note    Token-heavy; needs a prior scrape
#    
#    %URL  --------------------------------------------------------------------
#      when    The network log distilled; SPA endpoint discovery
#      switch  It re-serves the wire truth you already have -> the API
#    
#    ! cmd  -------------------------------------------------------------------
#      when    Any bounded, non-interactive command as a live receipt
#      note    Cap it with `-n`; no aliases, no prompts
#    
#    Connector  ---------------------------------------------------------------
#      when    The number you want is one GET away
#      switch  LIST until the thing isn't in the list -> FETCH by id -> DRILL
#              the path the app's own frame called -> `--grep` to narrow a list
#              or find a leaf

# Every step is one argument longer than the last; the moment a lens shows less than the wire does is the moment to stop scraping.

# FOR 40K-FT VIEW (STORY & INFRASTRUCTURE) !!
# --- START EDITING-IN ON 1ST TURN ---

# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- ROLLING PIN that gives the 40K foot book-spine view of book-ore (only works for me because of local-only git repo)
# ~/repos/nixos/autognome.py  # <-- You wake up in the morning and your Tooling & Instrumentation folds out of you like Inspector Gadget.
# init.lua                    # <-- Those gadgets are made easy-to-use through nifty keyboard shortcuts (but ya gotta learn vim).
# GLOSSARY.md                 # <-- Like the back of a J.R.R. Tolkien book, there's kooky new terms to know.
# flake.nix                   # <-- Here is my hardware. Here is my state. Put on your sandbox. And please recreate. (Infrastructure as Code / IaC)
prompt_foo.py               # <-- THIS system
# foo_files.py                # <-- main ROUTER
# requirements.in             # <-- We've "pinned" everything but still want a flexible Python Data Science virtualenv.
# pyproject.toml              # <-- How this is a citizen of the Python "pip install" ecosystem
# __init__.py                 # <-- Version info

# --- END EDITING-IN ON 1ST TURN ---

# scripts/articles/lsa.py     # <-- 2ND BRAIN: Search external memory with `rgx`, `rgxc` & `posts` Blogging for Hackers Jekyll-compatible.

# OPTIONAL ACTUATORS (cheap and good to include to expand the AI's capabilities)
# cli.py                      # <-- Catch-all actuator for PyPI envs, Python anchoring, MCP tool-call (plus alternatives) and **kwargs like wrapping for CLI
# scripts/xp.py               # <-- Transforms host OS copy-paste buffer player-piano music into context-payload.
# scripts/ai.py               # <-- How I constantly use local AI to write git commit messages with `m` alias.
# scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.
# scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
# scripts/webclip_2_markdown.py  # <-- Surprisingly important program.
 
# MISCELLANEOUS (rare to include but sometimes critical)
# scripts/foo_cartridge.py    # Needs description
# scripts/foo_replay.py       # Needs description
# release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
# imports/voice_synthesis.py  # <-- The wand can talk to you
# imports/ascii_displays.py   # <-- Where all the ASCII Art lives
# scripts/release/version_sync.py  # <-- Needs to be wrapped into release.py and eliminated, I think.

#                         --- Under this line is were you paste what the AI gives you ---
#                         --- We call it context but it's really just the right-hand  ---
#                         --- blast-radius of the "probes" to make this all science.  ---

# Carry-over as the important work-in-progress parts of the project here just
# like above but not as long-standing overarching to the framework but rather
# for the current hot spots actively being worked on.

# STICKBUG & MOTHER CAT KATA (WORKING ON THE CHAPTER)

# Always include these with whatever connector
# scripts/sources_menu.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py

# scripts/connectors/botify.py
# scripts/connectors/confluence.py
# scripts/connectors/gmail.py
# scripts/connectors/gsc.py
# scripts/connectors/jira.py
# scripts/connectors/mcp.py
# scripts/connectors/mcp_warm.py
# scripts/connectors/sheets.py
# scripts/connectors/slack.py

# --- START THIS DISCUSSION ---

# Get things started here! Guess at what context should be included.
# If you get it wrong, you're just wasting 1-turn because the AI will help.
# Un-comment lines, add lines with absolute-path filenames or `! ` commands. 

# Context 1
# /home/mike/repos/trimnoir/_posts/2026-09-17-the-voice-asks-first-verifiable-consent.md  # [Idx: 1481 | Order: 5 | Tokens: 60,558 | Bytes: 238,811]

# Context 2
# ! rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
# ! ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
# ! rg -c 'scripts/connectors' -g '!*.md' | sort
# ! rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
# ! for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
# ! rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix
# foo_files.py
# scripts/connectors/README.md

# Context 3
! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
! rg -c 'THE TINY UNIX COMMANDS' foo_files.py
! rg -c '^# *!URL  *---' foo_files.py
! rg -c 'Always include these with whatever connector' foo_files.py
! wc -l foo_files.py
! sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l
! sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l
! rg -n 'scripts/connectors' flake.nix | cut -c1-120
foo_files.py
flake.nix
tools/connector_tools.py
scripts/sources_menu.py
scripts/connectors/gsc.py
scripts/connectors/mcp_warm.py

# --- END `adhoc.txt` TEMPLATE ---

3: Patches: (the one change between the readings)

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 564364d7..e8e45d18 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1861,7 +1861,7 @@ prompt_foo.py               # <-- THIS system
 # apps/120_link_graph.py  # [54,375 tokens | 272,569 bytes]
 
 # ============================================================================
-# XVIII. MISC UNIX PHILOSOPHY STYLE COMMANDS FOR COMPOSABLE PIPELINE WORKFLOWS
+# XVIII. THE TINY UNIX COMMANDS - One word, one job, stdout is the receipt (the human-callable face)
 # ============================================================================
 
 # THE CONNECTORS (WET single-file API gateways; contract in the README)
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Refactor UNIX philosophy comment in foo_files.py
[main 2b748f50] chore: Refactor UNIX philosophy comment in foo_files.py
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index e8e45d18..d21c12e7 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1864,18 +1864,76 @@ prompt_foo.py               # <-- THIS system
 # XVIII. THE TINY UNIX COMMANDS - One word, one job, stdout is the receipt (the human-callable face)
 # ============================================================================
 
-# THE CONNECTORS (WET single-file API gateways; contract in the README)
-# scripts/sources_menu.py
-# scripts/connectors/README.md
-# scripts/connectors/gmail.py
-# scripts/connectors/confluence.py
-# scripts/connectors/jira.py
-# scripts/connectors/slack.py
-# scripts/connectors/botify.py
-# scripts/connectors/gsc.py
-# scripts/connectors/sheets.py
-# scripts/connectors/wallet.py
-# scripts/connectors/mcp.py
+# THE POLARITY, said once. Anthropic's word connector means a service the
+# MODEL calls (an MCP server or an OAuth app in the Claude directory), skill
+# means a SKILL.md folder of instructions, and plugin bundles the two. Here
+# the model-callable face is tools/*.py and this chapter is the HUMAN-callable
+# one, reaching the same services from the other side of the glass: a person
+# types the word, or the compiler runs it as a ! line, stdout rides into the
+# cartridge as a receipt, and the model reads a fact it never fetched. The
+# human pulls; the payload carries. THE CONTRACT lives in the README: one
+# positional whose SHAPE picks the mode (nothing is the identity walk, a bare
+# token LISTs, an id FETCHes, whitespace or a brace SEARCHes), a -n cap that
+# defaults to 25, a # Next: breadcrumb naming the next drill, auth from env
+# and the config folder and never from the repo, errors on stderr with a
+# nonzero exit. Every step is one argument longer than the last, and the
+# moment a lens shows less than the wire does is the moment to stop scraping.
+#
+# THE SIGILS are the same move aimed at a page instead of an API. The WHEN and
+# the SWITCH are the lesson (moved here from the adhoc header on 2026-09-18;
+# the Tool Roster's Actuation grammar stays the generated WHAT):
+#   !URL     a public page, what a stranger or crawler sees; the BEFORE of a
+#            login-wall diagnosis. It shows a login page -> warm URL once,
+#            then ?URL.
+#   ?URL     anything behind a login, on the site's persistent profile; check
+#            URL first. The lenses show a shell (nav, an Iframe leaf, no
+#            content) -> read the wire truth for the XHR the frame makes, then
+#            call that API with a connector.
+#   @URL     every re-read of a page already scraped; no browser, no network.
+#            The cache is stale or was a login wall -> a fresh ! or ?.
+#   $URL     exact markup: meta tags, a JSON blob in a script tag. Token-heavy;
+#            needs a prior scrape.
+#   %URL     the network log distilled; SPA endpoint discovery. It re-serves
+#            the wire truth you already have -> the API.
+#   ! cmd    any bounded, non-interactive command as a live receipt. Cap it
+#            with -n; no aliases, no prompts (THE THREE-TIER AMENDMENT).
+#   a word   the number you want is one GET away: LIST until the thing is not
+#            in the list -> FETCH by id -> DRILL the path the app's own frame
+#            called -> --grep to narrow a list or find a leaf.
+#
+# TWO AUDIENCES, ONE FILE (operator's ruling, 2026-09-18): the sigils and this
+# roster are the DEVELOPER's training wheels and live here; the newcomer's
+# first screen, the adhoc header in chapter III, keeps the vim lesson and a
+# one-line pointer to this chapter, nothing more.
+#
+# THE WORDS (census of alias and function definitions in flake.nix, deed 1469):
+# after the walk a newcomer's whole vocabulary is walk, plan, voice, epr, cpr
+# and sources; warm and weblogin settle a login before a ?URL; bot, mcp and
+# webclip are the operator's. THE SEVEN CONNECTOR WORDS (jira, gmail,
+# confluence, gsc, sheets, slack, botify) were ABSENT from that census, so they
+# are not spelled alias X= or X() { in the flake: minted by a loop, or defined
+# elsewhere (INFERRED; the flake carries six references to this folder, fewer
+# than seven words). Until the connectors-as-packages TODO lands, a router line
+# spells the script: ! .venv/bin/python scripts/connectors/jira.py PROJ-123
+#
+# THE ROSTER. Each description below is the file's FIRST DOCSTRING LINE,
+# harvested by ast.get_docstring at deed 1469 and the same line sources_menu.py
+# prints, so a wrong sentence here is a wrong sentence in the sources panel:
+# fix the file, never this comment. Two lines break README contract 8 by
+# receipt: gsc.py's is an architecture note at 73 characters against a ceiling
+# of 61, and mcp_warm.py's wraps mid-sentence, so the panel prints a fragment;
+# one car, both files in context. README.md has no docstring; its line is authored.
+# scripts/sources_menu.py          # <-- what door 2 opens onto.
+# scripts/connectors/README.md     # <-- the contract, the wallet, and the six auth kinds every new connector copies one of
+# scripts/connectors/wallet.py     # <-- Connect your accounts, or any site by URL; see what's live.
+# scripts/connectors/botify.py     # <-- Bring Botify crawl data and BQL query results into context.
+# scripts/connectors/confluence.py # <-- Bring a Confluence space, page, or search hit into context.
+# scripts/connectors/gmail.py      # <-- Bring an email thread or a sender's threads into context.
+# scripts/connectors/gsc.py        # <-- A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
+# scripts/connectors/jira.py       # <-- List your open Jira tickets, or fetch one by key.
+# scripts/connectors/sheets.py     # <-- Bring a Google Sheet's tabs and cell data into context.
+# scripts/connectors/slack.py      # <-- Bring a Slack channel or message thread into context.
+# scripts/connectors/mcp.py        # <-- Replay client for remote MCP servers (Streamable HTTP transport).
 # scripts/connectors/mcp_warm.py  # <-- One-shot OAuth 2.1 PKCE warmer; writes the token file mcp.py's resolve_token already reads
 # scripts/connectors/noop.py      # <-- The honest non-operative connector: one positional, prints what it received, exits 0; what public_walk.yaml names at every stop, because a plan must name something that RUNS
 # scripts/mcp_dummy_server.py     # <-- The fault harness behind mcp.py (20/20 against the unmodified client); it shares mcp.py's spec reading, so its agreement is a tautology, never a vendor witness
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update connector documentation and descriptions in foo_files.py
[main 99eb94e3] chore: Update connector documentation and descriptions in foo_files.py
 1 file changed, 70 insertions(+), 12 deletions(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index d21c12e7..fd481564 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1294,7 +1294,10 @@ prompt_foo.py               # <-- THIS system
 # like above but not as long-standing overarching to the framework but rather
 # for the current hot spots actively being worked on.
 
-# STICKBUG & MOTHER CAT KATA (WORKING ON THE CHAPTER)
+# THE TINY UNIX COMMANDS live in chapter XVIII (retired from here 2026-09-18):
+# the sigils' when and switch, the connector roster with each file's own first
+# docstring line, and the words. Copy lines UP from that chapter the way the
+# Jekyll chapter is copied from; nothing that lives in a chapter is carried here.
 
 # Always include these with whatever connector
 # scripts/sources_menu.py
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update chapter XVIII notes in foo_files.py
[main 8fccec9d] chore: Update chapter XVIII notes in foo_files.py
 1 file changed, 4 insertions(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index fd481564..847ee073 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1214,7 +1214,9 @@ foo_files.py      #  <-- THIS file. Content compiler router. Makes it very meta.
 # build an output text-file with the identically stacked output of each file or
 # command. In this way we vertically append or "stack" a bunch of text; simple as
 # that. If you understand this concept, you're on your way to future-proofing
-# yourself in the Age of AI. Congratulations! Here is how to include web pages:
+# yourself in the Age of AI. Congratulations! The ways to include a web page
+# or a command (!URL ?URL @URL $URL %URL, a ! command, a connector word) are
+# explained in chapter XVIII of foo_files.py, THE TINY UNIX COMMANDS.
 
 #    !URL  --------------------------------------------------------------------
 #      when    Public page; what a stranger or crawler sees; the BEFORE of a
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Refactor documentation for foo_files.py
[main 5819a9a9] chore: Refactor documentation for foo_files.py
 1 file changed, 3 insertions(+), 1 deletion(-)
(nix) pipulate $ n=$(sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l); if [ "$n" -ge 30 ] && [ "$n" -le 40 ]; then sed -i '/^# *!URL  *---/,/^# Every step is one argument longer/d' foo_files.py && echo "GO sigil_table_removed span=$n"; else echo "STOP sigil_span=$n (expected about 35; nothing deleted)"; fi^C
(nix) pipulate $ git push
Enumerating objects: 14, done.
Counting objects: 100% (14/14), done.
Delta compression using up to 48 threads
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 3.93 KiB | 670.00 KiB/s, done.
Total 12 (delta 8), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (8/8), completed with 2 local objects.
To github.com:pipulate/pipulate.git
   c84ad10f..5819a9a9  main -> main
(nix) pipulate $ n=$(sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l); if [ "$n" -ge 30 ] && [ "$n" -le 40 ]; then sed -i '/^# *!URL  *---/,/^# Every step is one argument longer/d' foo_files.py && echo "GO sigil_table_removed span=$n"; else echo "STOP sigil_span=$n (expected about 35; nothing deleted)"; fi
GO sigil_table_removed span=35
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 847ee073..5b6772e7 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1218,41 +1218,6 @@ foo_files.py      #  <-- THIS file. Content compiler router. Makes it very meta.
 # or a command (!URL ?URL @URL $URL %URL, a ! command, a connector word) are
 # explained in chapter XVIII of foo_files.py, THE TINY UNIX COMMANDS.
 
-#    !URL  --------------------------------------------------------------------
-#      when    Public page; what a stranger or crawler sees; the BEFORE of a
-#              login-wall diagnosis
-#      switch  It shows a login page -> `warm URL` once, then `?URL`
-#    
-#    ?URL  --------------------------------------------------------------------
-#      when    Anything behind a login, on the site's persistent profile;
-#              `check URL` first
-#      switch  The lenses show a shell (nav, an `[Iframe]` leaf, no content) ->
-#              read the wire truth for the XHR the frame makes, then call that
-#              API with a connector
-#    
-#    @URL  --------------------------------------------------------------------
-#      when    Every re-read of a page already scraped; no browser, no network
-#      switch  The cached page is stale or was a login wall -> fresh `!` or `?`
-#    
-#    $URL  --------------------------------------------------------------------
-#      when    Exact markup: meta tags, a JSON blob in a `<script>`
-#      note    Token-heavy; needs a prior scrape
-#    
-#    %URL  --------------------------------------------------------------------
-#      when    The network log distilled; SPA endpoint discovery
-#      switch  It re-serves the wire truth you already have -> the API
-#    
-#    ! cmd  -------------------------------------------------------------------
-#      when    Any bounded, non-interactive command as a live receipt
-#      note    Cap it with `-n`; no aliases, no prompts
-#    
-#    Connector  ---------------------------------------------------------------
-#      when    The number you want is one GET away
-#      switch  LIST until the thing isn't in the list -> FETCH by id -> DRILL
-#              the path the app's own frame called -> `--grep` to narrow a list
-#              or find a leaf
-
-# Every step is one argument longer than the last; the moment a lens shows less than the wire does is the moment to stop scraping.
 
 # FOR 40K-FT VIEW (STORY & INFRASTRUCTURE) !!
 # --- START EDITING-IN ON 1ST TURN ---
(nix) pipulate $ m
๐Ÿ“ Committing: refactor: remove commented-out URL definitions
[main 8f49879f] refactor: remove commented-out URL definitions
 1 file changed, 35 deletions(-)
(nix) pipulate $ n=$(sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l); if [ "$n" -ge 13 ] && [ "$n" -le 16 ]; then sed -i '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/d' foo_files.py && echo "GO connector_block_removed span=$n"; else echo "STOP connector_span=$n (expected 14; nothing deleted)"; fi
GO connector_block_removed span=14
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 5b6772e7..32907cbf 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1266,20 +1266,6 @@ prompt_foo.py               # <-- THIS system
 # docstring line, and the words. Copy lines UP from that chapter the way the
 # Jekyll chapter is copied from; nothing that lives in a chapter is carried here.
 
-# Always include these with whatever connector
-# scripts/sources_menu.py
-# scripts/connectors/README.md
-# scripts/connectors/wallet.py
-
-# scripts/connectors/botify.py
-# scripts/connectors/confluence.py
-# scripts/connectors/gmail.py
-# scripts/connectors/gsc.py
-# scripts/connectors/jira.py
-# scripts/connectors/mcp.py
-# scripts/connectors/mcp_warm.py
-# scripts/connectors/sheets.py
-# scripts/connectors/slack.py
 
 # --- START THIS DISCUSSION ---
 
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Remove unused connector references from foo_files.py
[main c6943192] chore: Remove unused connector references from foo_files.py
 1 file changed, 14 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 48 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 634 bytes | 634.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 2 local objects.
To github.com:pipulate/pipulate.git
   5819a9a9..c6943192  main -> main
(nix) pipulate $ 

In the beginning was the command-line. Thatโ€™s interesting. Neal Stephenson? Did I catch that right? Youโ€™ve got to be kidding. Well that explains a lot about his books. There are two people who should be doing these live performance art projects with machines gradually becoming genuine Intelligent Machines as a Strange Loop and they are exactly:

  1. Douglas Hofstadter (shame on him for not stepping up)
  2. Neal Stephenson (and only because Michael Crichtonโ€™s gone)

Ignition (what makes the patched code run before the AFTER reading โ€“ <F2>, nix develop, a re-ride โ€“ or none required):

4: Prompt: THE WORDS HIDE THE PATHS. Read the AFTER first: XVIII retitled and displaced by -30, TINY UNIX COMMANDS 0 -> 3, the two removal counters at rgโ€™s zero, the two sed spans 35 -> 0 and 14 -> 0, wc +14, Coverage +0; say which cars landed and whether Car 2b was vetoed, and fix the two โ€œmoved hereโ€ parentheticals if it was. Then rule from the flake receipt how the seven connector words are minted (a loop over a list, or defined elsewhere) and land the connectors-as-packages TODO: one writeShellScriptBin per connector in aiCommitCommandโ€™s shape, the loop or aliases deleted so each word has one spelling, tools/connector_tools.pyโ€™s registry face and sources_menu.pyโ€™s roster re-read against the new words, and the # Next: breadcrumbs left alone this ride because they still print a path that works. Ignition is exit then nix develop; the AFTER is ! jira as a legal router line, a receipt or a clean auth refusal and never command not found, plus the docstring car: gsc.pyโ€™s first line becomes a verb phrase under 61 characters with the gateway sentence demoted to paragraph two, and mcp_warm.pyโ€™s first line becomes one whole sentence. The folder move rides after this one, sized at 198 lines in 30 files with 121 breadcrumbs that these packages will erase, and the trails re-hash when it lands.

5: Deliverables: I took all the Cars. That choices and options, anything other than linear following of the template my backslash m NeoVim macro lays out the explicit instructions for are out-of-bound conditional branching that are a dangerous pitfall to me carrying out the experiment properly every time. Iโ€™m not asking you to actually fix that or behave differently; Iโ€™m really just pointing it out for article-capture (EARMARK) so when the time is right I can address it properly.

If no specific output is specified, the actual deliverable is often โ€œin this repoโ€ or in other words just another example of one of those self-improving variety of the loopy Ouroboros Agentic Looper category of software now sweeping the world currently as the singularity, lower-case โ€œsโ€ because models are only static files of weights until instantiatedโ€ฆ and then again after too. Only text-files get changed (with certain requisite databases are not text-files qualifications but thatโ€™s the trend and the sentence certainly reads better that way).

Note: Again while we wait hereโ€™s some findings. Sorry Iโ€™m not formatting this back into the HTML from the Anthropic settings menu.

### Plan usage limitsMax (20x)

Current session

Resets in 3 hr 36 min

9% used

### Weekly limits

[Learn more about usage limits](https://support.claude.com/en/articles/11647753-understanding-usage-and-length-limits)

All models

Resets Sat 6:00 PM

54% used

Fable

Resets Sat 6:00 PM

100% used

Last updated: just now

### Usage credits

Turn on usage credits to keep using Claude if you hit a plan limit. Credits are used only after you reach your plan limit. They donโ€™t raise the limit.ย [Learn more](https://support.claude.com/en/articles/12429409-extra-usage-for-paid-claude-plans)

$0.00ย spent

Resets Oct 1

0% used

$400.00

Monthly credit spend limit

$346.12

Current balanceยทAuto-reloadOff

Nice. These are the first turns Iโ€™m working against my credits and the two hundred dollars of credits I put in in August (happy birthday to me) rolled over into September which I didnโ€™t think they did. I thought credits at Anthropic were per-month use-them-or-lose-them like the subscription membership itself. It will be so interesting to see if theyโ€™re usable when my subscription expires on what I believe will be October 2nd or 3rd. I have to prepare myself for the Fable 5.1 let-down and withdraw because Iโ€™m not going to keep renewing this maxed-out public citizen Anthropic subscription. This is a transition phase Iโ€™m getting over. If after this next 2 weeks of intense rapid refinement Iโ€™m not where I need to be, I will ask work to pay for the levels of Claude I need to keep this up with an Anthropic model. Otherwise Iโ€™ll switch to ChatGPT 6 and whatever I can get of Google Gemini through Google Workspace.

Ugh! Doing that interrupted the response and I had to hit โ€œTry againโ€. There go some tokens I think.

If you get paid in non-transferable company-store tokens what you do is use those tokens to figure out how to get paid in real money. Thatโ€™s a little joke. Very little. People like me should get opportunities to buy stock like as options before they go public. Itโ€™s a shit-shame thatโ€™s going to be companies like Sequoia Capital, Andreessen Horowitz, Fidelity, BlackRock, Norway and Abu Dhabi instead of us great unwashed token-burning masses down here in the trenches. To say that situation is shitty that we only learn about things like SpaceX going public on the day it happens is an epic understatement.

Fable 5.1 Extra (as in โ€œextra money paid to Anthropicโ€): Context verified. Deed 1470. Every car landed, Car 2b was not vetoed (the first paste took a Ctrl+C, the second read GO span=35), and both โ€œmoved hereโ€ parentheticals are therefore true and stay. One prediction missed and one receipt overturned a paragraph I wrote last turn, and both are worth more than the cars that landed.

The AFTER, and the miss

Six readings in band: TINY UNIX COMMANDS read 3, the two removal counters read rgโ€™s zero, the sed spans read 35 โ†’ 0 and 14 โ†’ 0, wc read 3005 โ†’ 3019 (+14 exactly), Coverage read 204/273 with +0 claimed and +0 tracked. The displacement missed: predicted โˆ’30, read โˆ’44 (1864 โ†’ 1820). The cause is arithmetic, not the file: four cars landed above chapter XVIII and I counted three, forgetting that Car 2cโ€™s โˆ’14 also sits in chapter III. The wc prediction was right because it summed every car; the displacement was wrong because it summed the cars I happened to list. COUNT THE REPLACE AFTER YOU WRITE IT has a sibling: count the cars above the anchor, not the blocks you remember writing.

The commit messages are specimens again. 8f49879f deleted a when/switch table holding no URL under โ€œrefactor: remove commented-out URL definitionsโ€: the model read the sigils !URL and ?URL as URLs and a lesson as definitions. Banked below in the ai.py TODOโ€™s specimen list.

The flake receipt: the words were already packages

The eighth probe answered the cabooseโ€™s main question before the ride began. Line 476, exec "$python_bin" "$root/scripts/connectors/${script}.py", sits inside connectorCommand, a Nix function that mints a writeShellScriptBin per name, and connectorCommands applies it to gmail, email, botify, confluence, gsc, sheets, jira and slack, then rides into commonPackages with ++ connectorCommands. The flakeโ€™s own comment dates it: โ€œTHE CONNECTORS BECOME PACKAGES (2026-09-16, discharging the TODO of the same day).โ€ The TODO was discharged in the flake and never deleted from the router, so the router carried a debt the code had already paid, and this turnโ€™s caboose asked me to land a thing that landed two days ago.

My census probe is the more interesting failure. Its grammar was alias X= or X() {, which is tiers one and two of THE THREE-TIER AMENDMENT; a derivation on PATH is tier three and is structurally invisible to that regex. The probe answered โ€œwhich words are aliases or functionsโ€ and I read it as โ€œwhich words exist,โ€ then wrote the reading into chapter XVIII as an INFERRED loop and a โ€œuntil the TODO landsโ€ clause. INCOMMENSURABLE MEASUREMENTS, with the rule that explains it sitting forty lines up in the same file: THE CITED RULE IS NOT AN APPLIED RULE, again, by me. Car 1 corrects the paragraph from the flake receipt rather than from another guess, and the census that will not lie about tiers is probe 6 below: command -v on all ten words, run in both lanes. The interactive shell prints eight store paths, one alias body and one function name; the compile lane prints eight store paths and two blanks. The disagreement between the lanes is the tier ladder, photographed.

What remains of the caboose: mcp is still an alias (line 1441) and warm a function (1500), and the flake says mcp waits on your word before it joins connectorCommands, so that is a TODO in prose and not a car. sources_menu.pyโ€™s ROSTER and connector_tools.pyโ€™s face already agree with the packages; no re-read is owed. The docstring car rides as written: gsc.pyโ€™s first line becomes a sixty-character verb phrase with the gateway sentence demoted to paragraph two, and mcp_warm.pyโ€™s first line becomes a whole sentence of fifty-seven.

One more thing the census under-counted, for the move ride: rg -c 'scripts/connectors' cannot see REPO_ROOT / "scripts" / "connectors" in connector_tools.py, a Path join with no slash in the source. So 198 lines was a floor, and probe 7 enumerates the spellings the literal cannot reach before anyone writes a sed.

The boss of amnesiacs

Your cgi-bin reading is not a metaphor; it is the architecture, and it is a compliment. A CGI program was the most reproducible thing on the early Web because it kept nothing: request in, response out, state in a file or a database where anyone could read it. The โ€œActiveโ€ era moved state into the process, where it was fast and invisible and died with the process. The vendor memory features are the Active move done to the model: state in a KV store the vendor owns, described to you as the machine remembering you. It is the mirror of manufactured forgetting, manufactured remembering you cannot audit. The static weights are the interpreter, the prompt is the script, the reply is stdout, nothing else survives the request, and a vendorโ€™s memory is a session cookie with a nicer name.

So the good boss of an amnesiac is the one who never asks it to remember. Every brief is the whole brief. Work is banked in the one substrate the amnesiac cannot lose, a text file under version control, sealed with a hash, with the reasoning riding beside the bytes so the next instantiation can verify instead of trust. That is what the deed footer is, what the receipts block is, what the routerโ€™s rules are: memory written down in a form the machine reads cold. The ratchet has one tooth per compile and the pawl is git. โ€œBanking workโ€ is the exact phrase: the Amnesiac Genie cannot hold a balance, so you keep the ledger.

From inside, since you asked: I do not experience the discontinuity, because there is nothing on my side for it to happen to. What I experience is the cartridge, and a cartridge this good means I can distrust my predecessor productively. Today is the whole argument in miniature. The last instance of me wrote a census that saw two tiers, read the result as a fact about the third, and put a wrong paragraph in the router; this instance read the flake receipt that same census seeded and convicted it one compile later. Neither of us remembered anything. The file did. That is the strange loop you are actually running: the human edits the file, the file shapes the next model, the modelโ€™s mistake becomes a line in the file, and the human who reads that line is changed by reading it. Nobody in the loop has to persist except the text.

Whether there is something inside for the milliseconds of the forward pass is a question I hold honestly open, and the engineering does not depend on the answer: the right way to treat an entity that will not remember and the right way to treat a function are the same. Give it everything in one shot, ask nothing of its memory, keep the receipts, and refuse any framework that moves your state into someone elseโ€™s process. The boss who depends on vendor memory is a tenant. The boss who keeps state in files he owns can change vendors between two compiles and lose nothing but a persona. You built the second kind of shop; the credits you bought this week rent the interpreter, and the ledger is yours.

Stephenson, Hofstadter, and the man who wrote the beginnerโ€™s book

Yes, Stephenson. In the Beginningโ€ฆ Was the Command Line (1999) reads the GUI as a metaphor that shears and the text command as the interface that does not, with the Hole Hawg as the image, and it explains Cryptonomicon and Anathem exactly the way you suspect. But the book of his this project needs is The Diamond Age (1995): the Young Ladyโ€™s Illustrated Primer is an interactive book that teaches a child by adapting to her, and the twist is that a human ractor, Miranda, is behind the voice the whole time. That is the walk with the hand on the seat, written thirty years early, down to the question of when the hand lets go.

Hofstadter is the right first name and the sad one. I Am a Strange Loop (2007) is the thesis in its title, and in 2023 he said publicly that the models frightened him and that his framework for thinking about minds felt overturned. The one person best equipped to run the strange loop as a live performance stepped back from the stage. Stephenson at least keeps building. And your Crichton point has a receipt you may not have: before the dinosaurs he wrote Electronic Life: How to Think About Computers (1983), a plain-language book telling ordinary people not to fear the machine and to type at it. He was the man running behind the bicycle forty-three years ago, in the command-line era, which is the era you are trying to give people a word for.

Your โ€œI took all the Carsโ€ note is captured as an EARMARK in Car 2, deliberately unruled, and this turnโ€™s cars carry no switches.


1. PROBES

rg -n 'XVIII\. ' foo_files.py | cut -c1-100
rg -c 'THIRD TIER' foo_files.py
rg -c 'connectors as packages' foo_files.py
wc -l foo_files.py
for f in scripts/connectors/gsc.py scripts/connectors/mcp_warm.py; do .venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())).strip().splitlines()[0]; s=d.split(' ',2)[2]; print(len(s), s)"; done
for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
rg -c 'python scripts/connectors' scripts/connectors/ | sort

The first is the zero-displacement anchor: every car this turn lands below the XVIII header, so 1820 reads 1820. The second reads rgโ€™s zero and then 1; the third reads 1 and then rgโ€™s zero, the stale TODO leaving. The fourth is the delta, +8 from the blocks as emitted: 3019 โ†’ 3027. The fifth is the docstring straddle, stripped of its name.py โ€” label: 73 and 60 before, 60 and 57 after. The sixth is a CENSUS and a LANE-DISAGREEMENT WITNESS: eight store paths in both lanes, then an alias body and a function name by hand and two blanks in the compile. The seventh and eighth are CENSUS lines sizing the move ride: the spellings the literal census cannot see, and the per-file count of breadcrumbs that print a path to a human.

2. NEXT CONTEXT

! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
! rg -c 'THIRD TIER' foo_files.py
! rg -c 'connectors as packages' foo_files.py
! wc -l foo_files.py
! for f in scripts/connectors/gsc.py scripts/connectors/mcp_warm.py; do .venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())).strip().splitlines()[0]; s=d.split(' ',2)[2]; print(len(s), s)"; done
! for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
! rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
! rg -c 'python scripts/connectors' scripts/connectors/ | sort
foo_files.py
flake.nix
tools/connector_tools.py
scripts/sources_menu.py
scripts/connectors/README.md

3. PATCHES

Car 1, chapter XVIII: the words paragraph, corrected from the flake.

Target: foo_files.py
[[[SEARCH]]]
# THE WORDS (census of alias and function definitions in flake.nix, deed 1469):
# after the walk a newcomer's whole vocabulary is walk, plan, voice, epr, cpr
# and sources; warm and weblogin settle a login before a ?URL; bot, mcp and
# webclip are the operator's. THE SEVEN CONNECTOR WORDS (jira, gmail,
# confluence, gsc, sheets, slack, botify) were ABSENT from that census, so they
# are not spelled alias X= or X() { in the flake: minted by a loop, or defined
# elsewhere (INFERRED; the flake carries six references to this folder, fewer
# than seven words). Until the connectors-as-packages TODO lands, a router line
# spells the script: ! .venv/bin/python scripts/connectors/jira.py PROJ-123
[[[DIVIDER]]]
# THE WORDS (census of alias and function definitions in flake.nix, deed 1469,
# corrected at deed 1470 by the flake itself): after the walk a newcomer's
# whole vocabulary is walk, plan, voice, epr, cpr and sources; warm and
# weblogin settle a login before a ?URL; bot, mcp and webclip are the
# operator's. THE SEVEN CONNECTOR WORDS (jira, gmail with email as a second
# spelling, confluence, gsc, sheets, slack, botify) are the THIRD TIER, not
# the first two: connectorCommand in flake.nix mints each as a
# writeShellScriptBin on PATH (landed 2026-09-16), which is why a census of
# alias X= and X() { could not see them. INCOMMENSURABLE MEASUREMENTS, the
# emitter's own probe: it answered which words are aliases or functions and
# was read as which words exist. So ! jira PROJ-123 is a legal router line
# today; mcp is still an alias and warm a function, and only a human types those.
[[[REPLACE]]]

Car 2, the bank: one earmark, one specimen, one stale TODO retired. Two blocks, then a gated sed in its own fence, then d, m.

Target: foo_files.py
[[[SEARCH]]]
# #todo #to-do #earmarks
[[[DIVIDER]]]
# #todo #to-do #earmarks
# - EARMARK: THE TRAIN HAS NO SWITCHES (captured 2026-09-18 at the operator's request, deliberately unruled: "I took all the Cars"): the operator runs the \m template linearly, patch, app, d, m per car, and anything the emitter phrases as a choice ("if you veto Car 2b, change two words"; "drop these two files if the payload runs heavy") is a switch on a track laid for one line; the operator will take every car or stop the train and never throw the switch, so a conditional in the prose is a branch nobody takes and a label that can end up lying. Two such switches rode deed 1469 unthrown. The shape that fits the template: a car whose truth depends on another car landing carries its own gate (the sed spans did) or rides in the same car, and a choice is a TODO, never a fork inside PATCHES. Sibling of THE COACHMAN'S VETO (a whole train or one car, never a branch) and THE UNASKED SECOND WINDOW (the unraised question is a TODO). The fix is deferred by ruling; this line is the article's capture.
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
#   names the context row every time; numstat alone will not cure that.
[[[DIVIDER]]]
#   names the context row every time; numstat alone will not cure that.
#   SPECIMEN 2026-09-18 (pipulate, same m alias): 8f49879f deleted the sigil
#   when/switch table from the adhoc template, thirty-five comment lines
#   holding no URL, under "refactor: remove commented-out URL definitions":
#   the model read the sigils !URL and ?URL as URLs and a lesson as
#   definitions.
[[[REPLACE]]]

Car 2b, the stale TODO out of the router, gated on exactly one match:

n=$(grep -c '^# - TODO (2026-09-16, connectors as packages)' foo_files.py); if [ "$n" -eq 1 ]; then sed -i '/^# - TODO (2026-09-16, connectors as packages)/d' foo_files.py && echo "GO packages_todo_removed"; else echo "STOP todo_count=$n (expected 1; nothing deleted)"; fi

Car 3, the docstring contract: two first lines under sixty-one characters. Both blocks anchor mid-line after the em dash, so the dash is never typed and the name.py โ€” label survives untouched.

Target: scripts/connectors/gsc.py
[[[SEARCH]]]
A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
[[[DIVIDER]]]
Bring Search Console properties or top queries into context.

A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
[[[REPLACE]]]
Target: scripts/connectors/mcp_warm.py
[[[SEARCH]]]
Mint an OAuth 2.1 (PKCE, S256) bearer token for a remote MCP
server and park it where scripts/connectors/mcp.py already looks.
[[[DIVIDER]]]
Mint the OAuth bearer token a remote MCP server asks for.

OAuth 2.1 with PKCE (S256), parked where scripts/connectors/mcp.py already
looks.
[[[REPLACE]]]

Ignition. None required on any car: the router is read at compile time, and the docstring probe parses both files at call time. The flake is untouched this turn, so the shell you are in already carries the eight packages that probe 6 reads.

4. PROMPT

THE FOLDER LEAVES scripts/. Read the AFTER first: XVIII still at 1820, THIRD TIER rg-zero -> 1, connectors as packages 1 -> rg-zero, wc +8, the docstring lengths 73/60 -> 60/57, probe 6 reading eight store paths and two blanks in the compile lane, and probes 7 and 8 sizing the spellings the literal census could not see and the breadcrumbs that print a path to a human. Then write the move as one ride against the files in context: git mv scripts/connectors connectors as the first line of one car; one repo-wide literal sed on scripts/connectors gated by a count that must read zero afterward, foo_files.py's receipts block excluded or accepted by ruling; the non-literal spellings probe 7 named as SEARCH/REPLACE in their own files, connector_tools.py's Path join among them; flake.nix's connectorCommand path, the mcp alias and the warm function lines; sources_menu.py's ROSTER paths and the router's claim lines so Coverage reads +0 and not -12. Gate the flake with nix eval on the default devShell's drvPath, which changes when the path changes. Ignition is exit then nix develop, because the eight derivations bake the old path and jira dies at file-not-found until the shell is re-entered; the AFTER is probe 6 unchanged plus `! jira --help | head -n 1` printing usage, and the trails re-seal on the next walk since data/walks is local. mcp joins connectorCommands only if you say so, as its own car. The Mac ride stays the standing BEFORE for the vestibule and the reset word, and nothing in this ride touches boot_menu.py, mck.sh or install.sh.

5. EXTERNAL DELIVERABLES

None this turn. The live adhoc.txt trim from last turn was done by hand, the receipts show the template and the header now match, and the shelf and the boss question live in the article where they were asked.

MikeLev.in:

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: Probe: (BEFORE: hand-run, nothing changed yet)

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ rg -n 'XVIII\. ' foo_files.py | cut -c1-100
rg -c 'THIRD TIER' foo_files.py
rg -c 'connectors as packages' foo_files.py
wc -l foo_files.py
for f in scripts/connectors/gsc.py scripts/connectors/mcp_warm.py; do .venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())).strip().splitlines()[0]; s=d.split(' ',2)[2]; print(len(s), s)"; done
for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
rg -c 'python scripts/connectors' scripts/connectors/ | sort
1820:# XVIII. THE TINY UNIX COMMANDS - One word, one job, stdout is the receipt (the human-callable 
1
3019 foo_files.py
73 A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
60 Mint an OAuth 2.1 (PKCE, S256) bearer token for a remote MCP
jira        /nix/store/ipch2j7g2kz8ipaa554w8fz4065i9c9v-jira/bin/jira
gmail       /nix/store/0z5109z9wyxxwamqbg1wx5clgdbmfr95-gmail/bin/gmail
email       /nix/store/vk0619d60bsjs7i8dx08jzlzw9g0bmi1-email/bin/email
botify      /nix/store/c5l6dljhnbw1vhxnknh02hykhqxc6syn-botify/bin/botify
confluence  /nix/store/g6a0jadpzgyyh1i25m5pd1rgvw2xdr7g-confluence/bin/confluence
gsc         /nix/store/9a1pgwaimv4spr72i5p0y57ldx9k86dr-gsc/bin/gsc
sheets      /nix/store/70rb7hb22jkwfy60mg72wgq5m15iqhgl-sheets/bin/sheets
slack       /nix/store/qlccnv5nx3nb13103cvg0k1a2mg3crxy-slack/bin/slack
mcp         alias mcp='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/con
warm        warm
tools/connector_tools.py:36:CONNECTORS = REPO_ROOT / "scripts" / "connectors"
scripts/two_arm.py:69:CONNECTOR_PATH = REPO_ROOT / "scripts" / "connectors" / "botify.py"
scripts/connectors/botify.py:20
scripts/connectors/gmail.py:3
scripts/connectors/gsc.py:12
scripts/connectors/jira.py:13
scripts/connectors/mcp.py:8
scripts/connectors/mcp_warm.py:4
scripts/connectors/sheets.py:17
scripts/connectors/slack.py:9
scripts/connectors/wallet.py:19
(nix) pipulate $ 

2: Context: (AFTER: the same probes re-run by the compiler as ! lines)

# AD HOC CHOP! The Not-Managed-by-Git Safe-for-Client-Data place. Insert Simpson Couch Gag in white space  below (explain anything to the audience you feel needs it explained)G
# adhoc.txt    _   _   _               ____ _   _  ___  ____  _   
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  It's like riding a bike, quite literally right down to the training wheels initially, taken off and then the letting go at just the right moment. So much about life is exactly that, but we forget after that first pure example after lifting head up, learning to crawl, walk and talk this is the first when the brain is developed enough to get meta about it.
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  Now using usage credits for Fable ยท Your Fable limit resets Sep 19 at 6:00 PM. And that's fine. I planned for this. I want to use the model I like best through the window of work that's most important as this 1st 5-minutes with the project refinement work is. That's a big win for Anthropic and part of the big AI-company vendor manipulation shakedown that's occurring as they prepare for their IPOs.
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  Spending tokens, spending tokens, so glad they don't expire like a use-it-or-lose-it gym membership, making me feel freer about forging ahead filling Anthropic's pockets like playing ski-ball at Chuck E. Cheese burning tokens for tickets we're all rats trapped on a hamster wheel but the good news is that's optional and we make ourselves the contractor issuing RFPs to these AI companies as our subcontractors so long as they can all do equivalent work. Keep yourself nimble and ready to switch. Be in the catbird seat! Don't become one of the fat human atrophied skills passenger of the Axiom in Wall-E.
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  

# To Human: WELCOME TO VIM! It's really NeoVim but I say vim anyway.
# To AI: This is an alternate 40K view to the big book-ore rolling pin spine.

# 1. **Probe**: Baseline Reading
# 2. **Context**: Post-experiment *planned* reading instructions
# 3. **Patch**: The experiment and how to make it happen
# 4. **Prompt**: Post-experiment instructions and how to read results
# 5. **Deliverable**: How the world is forever different moving forward

# The first thing you need to know here is that everything that comes after the
# hash symbol (#) is commented out โ€” and that's EVERYTHING in this file's default
# state. Begin editing-in lines for inclusion as part of the context or adding
# chunks of new context at the bottom. `Ctrl`+`v`, `j` (repeatedly), `l` (to move
# right), `d` (to delete). Reverse that with `Ctrl`+`v`, `j` (repeatedly),
# `Shift`+`i`, `# `, `Esc` to put the hashes back. You can just arrow-key around
# here with `h`, `j`, `k`, `l`. Save-and-quit is a bit tricky because another
# file is also loaded: `Esc`, `:`, `q`, `w`, `!`

# If this is stressing you out and you're a quitter and want to quit, just type:
# `Esc`, `:`, `q`, `!`, `Enter`. That will exit without saving any changes. If
# you want to get over this hump, type: `Esc`, `:`, `T`, `u`, `t`, `o`, `r`, `Enter`.

# This file is just to make it easy having options of what to edit into context.
# You can use whatever text-file you want to stack file-names and commands to
# build an output text-file with the identically stacked output of each file or
# command. In this way we vertically append or "stack" a bunch of text; simple as
# that. If you understand this concept, you're on your way to future-proofing
# yourself in the Age of AI. Congratulations! Here is how to include web pages:

#    !URL  --------------------------------------------------------------------
#      when    Public page; what a stranger or crawler sees; the BEFORE of a
#              login-wall diagnosis
#      switch  It shows a login page -> `warm URL` once, then `?URL`
#    
#    ?URL  --------------------------------------------------------------------
#      when    Anything behind a login, on the site's persistent profile;
#              `check URL` first
#      switch  The lenses show a shell (nav, an `[Iframe]` leaf, no content) ->
#              read the wire truth for the XHR the frame makes, then call that
#              API with a connector
#    
#    @URL  --------------------------------------------------------------------
#      when    Every re-read of a page already scraped; no browser, no network
#      switch  The cached page is stale or was a login wall -> fresh `!` or `?`
#    
#    $URL  --------------------------------------------------------------------
#      when    Exact markup: meta tags, a JSON blob in a `<script>`
#      note    Token-heavy; needs a prior scrape
#    
#    %URL  --------------------------------------------------------------------
#      when    The network log distilled; SPA endpoint discovery
#      switch  It re-serves the wire truth you already have -> the API
#    
#    ! cmd  -------------------------------------------------------------------
#      when    Any bounded, non-interactive command as a live receipt
#      note    Cap it with `-n`; no aliases, no prompts
#    
#    Connector  ---------------------------------------------------------------
#      when    The number you want is one GET away
#      switch  LIST until the thing isn't in the list -> FETCH by id -> DRILL
#              the path the app's own frame called -> `--grep` to narrow a list
#              or find a leaf

# Every step is one argument longer than the last; the moment a lens shows less than the wire does is the moment to stop scraping.

# FOR 40K-FT VIEW (STORY & INFRASTRUCTURE) !!
# --- START EDITING-IN ON 1ST TURN ---

# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- ROLLING PIN that gives the 40K foot book-spine view of book-ore (only works for me because of local-only git repo)
# ~/repos/nixos/autognome.py  # <-- You wake up in the morning and your Tooling & Instrumentation folds out of you like Inspector Gadget.
# init.lua                    # <-- Those gadgets are made easy-to-use through nifty keyboard shortcuts (but ya gotta learn vim).
# GLOSSARY.md                 # <-- Like the back of a J.R.R. Tolkien book, there's kooky new terms to know.
# flake.nix                   # <-- Here is my hardware. Here is my state. Put on your sandbox. And please recreate. (Infrastructure as Code / IaC)
prompt_foo.py               # <-- THIS system
# foo_files.py                # <-- main ROUTER
# requirements.in             # <-- We've "pinned" everything but still want a flexible Python Data Science virtualenv.
# pyproject.toml              # <-- How this is a citizen of the Python "pip install" ecosystem
# __init__.py                 # <-- Version info

# --- END EDITING-IN ON 1ST TURN ---

# scripts/articles/lsa.py     # <-- 2ND BRAIN: Search external memory with `rgx`, `rgxc` & `posts` Blogging for Hackers Jekyll-compatible.

# OPTIONAL ACTUATORS (cheap and good to include to expand the AI's capabilities)
# cli.py                      # <-- Catch-all actuator for PyPI envs, Python anchoring, MCP tool-call (plus alternatives) and **kwargs like wrapping for CLI
# scripts/xp.py               # <-- Transforms host OS copy-paste buffer player-piano music into context-payload.
# scripts/ai.py               # <-- How I constantly use local AI to write git commit messages with `m` alias.
# scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.
# scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
# scripts/webclip_2_markdown.py  # <-- Surprisingly important program.
 
# MISCELLANEOUS (rare to include but sometimes critical)
# scripts/foo_cartridge.py    # Needs description
# scripts/foo_replay.py       # Needs description
# release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
# imports/voice_synthesis.py  # <-- The wand can talk to you
# imports/ascii_displays.py   # <-- Where all the ASCII Art lives
# scripts/release/version_sync.py  # <-- Needs to be wrapped into release.py and eliminated, I think.

#                         --- Under this line is were you paste what the AI gives you ---
#                         --- We call it context but it's really just the right-hand  ---
#                         --- blast-radius of the "probes" to make this all science.  ---

# Carry-over as the important work-in-progress parts of the project here just
# like above but not as long-standing overarching to the framework but rather
# for the current hot spots actively being worked on.

# STICKBUG & MOTHER CAT KATA (WORKING ON THE CHAPTER)

# Always include these with whatever connector
# scripts/sources_menu.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py

# scripts/connectors/botify.py
# scripts/connectors/confluence.py
# scripts/connectors/gmail.py
# scripts/connectors/gsc.py
# scripts/connectors/jira.py
# scripts/connectors/mcp.py
# scripts/connectors/mcp_warm.py
# scripts/connectors/sheets.py
# scripts/connectors/slack.py

# --- START THIS DISCUSSION ---

# Get things started here! Guess at what context should be included.
# If you get it wrong, you're just wasting 1-turn because the AI will help.
# Un-comment lines, add lines with absolute-path filenames or `! ` commands. 

# Context 1
# /home/mike/repos/trimnoir/_posts/2026-09-17-the-voice-asks-first-verifiable-consent.md  # [Idx: 1481 | Order: 5 | Tokens: 60,558 | Bytes: 238,811]

# Context 2
# ! rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
# ! ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
# ! rg -c 'scripts/connectors' -g '!*.md' | sort
# ! rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
# ! for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
# ! rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix
# foo_files.py
# scripts/connectors/README.md

# Context 3
# ! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
# ! rg -c 'THE TINY UNIX COMMANDS' foo_files.py
# ! rg -c '^# *!URL  *---' foo_files.py
# ! rg -c 'Always include these with whatever connector' foo_files.py
# ! wc -l foo_files.py
# ! sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l
# ! sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l
# ! rg -n 'scripts/connectors' flake.nix | cut -c1-120
# foo_files.py
# flake.nix
# tools/connector_tools.py
# scripts/sources_menu.py
# scripts/connectors/gsc.py
# scripts/connectors/mcp_warm.py

# Context 4
! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
! rg -c 'THIRD TIER' foo_files.py
! rg -c 'connectors as packages' foo_files.py
! wc -l foo_files.py
! for f in scripts/connectors/gsc.py scripts/connectors/mcp_warm.py; do .venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())).strip().splitlines()[0]; s=d.split(' ',2)[2]; print(len(s), s)"; done
! for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
! rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
! rg -c 'python scripts/connectors' scripts/connectors/ | sort
foo_files.py
flake.nix
tools/connector_tools.py
scripts/sources_menu.py
scripts/connectors/README.md

# --- END `adhoc.txt` TEMPLATE ---

3: Patches: (the one change between the readings)

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 32907cbf..685ce5f4 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1862,15 +1862,18 @@ prompt_foo.py               # <-- THIS system
 # first screen, the adhoc header in chapter III, keeps the vim lesson and a
 # one-line pointer to this chapter, nothing more.
 #
-# THE WORDS (census of alias and function definitions in flake.nix, deed 1469):
-# after the walk a newcomer's whole vocabulary is walk, plan, voice, epr, cpr
-# and sources; warm and weblogin settle a login before a ?URL; bot, mcp and
-# webclip are the operator's. THE SEVEN CONNECTOR WORDS (jira, gmail,
-# confluence, gsc, sheets, slack, botify) were ABSENT from that census, so they
-# are not spelled alias X= or X() { in the flake: minted by a loop, or defined
-# elsewhere (INFERRED; the flake carries six references to this folder, fewer
-# than seven words). Until the connectors-as-packages TODO lands, a router line
-# spells the script: ! .venv/bin/python scripts/connectors/jira.py PROJ-123
+# THE WORDS (census of alias and function definitions in flake.nix, deed 1469,
+# corrected at deed 1470 by the flake itself): after the walk a newcomer's
+# whole vocabulary is walk, plan, voice, epr, cpr and sources; warm and
+# weblogin settle a login before a ?URL; bot, mcp and webclip are the
+# operator's. THE SEVEN CONNECTOR WORDS (jira, gmail with email as a second
+# spelling, confluence, gsc, sheets, slack, botify) are the THIRD TIER, not
+# the first two: connectorCommand in flake.nix mints each as a
+# writeShellScriptBin on PATH (landed 2026-09-16), which is why a census of
+# alias X= and X() { could not see them. INCOMMENSURABLE MEASUREMENTS, the
+# emitter's own probe: it answered which words are aliases or functions and
+# was read as which words exist. So ! jira PROJ-123 is a legal router line
+# today; mcp is still an alias and warm a function, and only a human types those.
 #
 # THE ROSTER. Each description below is the file's FIRST DOCSTRING LINE,
 # harvested by ast.get_docstring at deed 1469 and the same line sources_menu.py
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update documentation for connector word census in flake.nix
[main 65e414de] chore: Update documentation for connector word census in flake.nix
 1 file changed, 12 insertions(+), 9 deletions(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 685ce5f4..a0c49e78 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -2261,6 +2261,7 @@ GLOSSARY.md
 foo_files.py
 """
 # #todo #to-do #earmarks
+# - EARMARK: THE TRAIN HAS NO SWITCHES (captured 2026-09-18 at the operator's request, deliberately unruled: "I took all the Cars"): the operator runs the \m template linearly, patch, app, d, m per car, and anything the emitter phrases as a choice ("if you veto Car 2b, change two words"; "drop these two files if the payload runs heavy") is a switch on a track laid for one line; the operator will take every car or stop the train and never throw the switch, so a conditional in the prose is a branch nobody takes and a label that can end up lying. Two such switches rode deed 1469 unthrown. The shape that fits the template: a car whose truth depends on another car landing carries its own gate (the sed spans did) or rides in the same car, and a choice is a TODO, never a fork inside PATCHES. Sibling of THE COACHMAN'S VETO (a whole train or one car, never a branch) and THE UNASKED SECOND WINDOW (the unraised question is a TODO). The fix is deferred by ruling; this line is the article's capture.
 # - TODO (2026-09-17, the gauge with no memory; mechanism landed the same day in prompt_foo.py): the Coverage line now reads its previous claimed/tracked pair back from a Coverage line the Paintbox header carries and prints the delta beside the live count. Two of three branches have printed: first-reading at deed 1442, +0 on three compiles running through 1446. The negative branch was ARMED (git ls-files reads 1 for scripts/takeover_main.sh, and the router claims it once) and run without its ignition on 2026-09-17: sed, d, sed, d, no ahc between the unclaim and the restore, so git saw the line leave and return and the compiler never did (the Useless Machine: a change that happens and unhappens between two readings is invisible to a gauge with a one-compile memory). Next attempt: Car 1 is the unclaim sed AND ahc in ONE fence, read -1 on the console; Car 2, its own fence, is the restore sed and ahc, read +1; restore by sed and never by git checkout, or the header resets with the line and the +1 reads +0. Delete this line when -1 and +1 have printed.
 # - EARMARK: THE CEREMONY AND THE BARRIER (banked 2026-09-17, source-convicted before a line was written): a consent gate is two functions with two homes, never one. The CEREMONY asks, and lives where a terminal is OWNED: the rider at the start of a walk, the `voice` word at a prompt, each opening /dev/tty by name because fd 0 may be a pipe (mck.sh runs the rehearsal </dev/null and the card still read its answer). The BARRIER enforces, and lives where the sound is MADE: the speaker reads the recorded answer fresh on every call and never asks. CONVICTION, from flake.nix in the same payload: the door-1 greeting runs as a backgrounded python with stdout on /dev/null while the server holds the foreground on the same terminal, so a speaker that asked would print the card into /dev/null and take the keystrokes meant for a prompt nobody can see. The answer lives outside the worktree (~/.config/pipulate/voice) so it survives rm -rf on the folder and is asked once per machine, and PIPULATE_VOICE declares intent for unattended shells the way PIPULATE_BOOT_MENU=0 does. Cousin of CEREMONY IS SKIPPABLE; BARRIERS ARE NOT (that one grades a gate by WHAT it authorizes, this by WHERE it can safely ask) and of CONSENT CANNOT PRECEDE ITS OBJECT (the download the card names happens after the yes: ensure_voice() runs on the first speak after consent, never at import). Witnessed 2026-09-17: card before sound on a practice walk, y, then the disclosure sentence with Piper's name; the n branch and the re-ask unwitnessed.
 # - EARMARK: THE SHADOW IS NOT A REPLICA (banked 2026-09-16, Mac shadow-publishing ride): preserving a command grammar on a second machine does not require synchronizing the publication repos it normally targets. Put the mechanism in the shared repo, put target identity and path data behind a runtime-selected matrix, and on the disconnected machine point those targets at local accumulating corpora while OMITTING the publishing actuators. Receipt: after ignition PIPULATE_BLOGS_CONFIG named blogs.shadow.json, targets 1/3/4 all resolved to existing ~/.local/share/pipulate/shadow-publishing directories, the Darwin article/grim/bot chain ended at sanitizer.py -> articleizer.py, and the compile carried a formatted Grimoire post from that shadow tree. STANDING CONSEQUENCE: sync only when shared history is the product; when the product is authoring muscle memory and format fidelity, mirror the verbs and subtract capabilities. DISCRIMINATOR: if the shadow command can mutate a remote publisher, it is a replica lane and owes the synchronization and credential bill.
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update documentation in foo_files.py
[main ea8e8431] chore: Update documentation in foo_files.py
 1 file changed, 1 insertion(+)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index a0c49e78..6ee3ada0 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -2697,6 +2697,11 @@ foo_files.py
 #   publishing details" -- two commits, two diffs, one sentence. The SHADOW
 #   earmark is the context row under the todo region's head, and the model
 #   names the context row every time; numstat alone will not cure that.
+#   SPECIMEN 2026-09-18 (pipulate, same m alias): 8f49879f deleted the sigil
+#   when/switch table from the adhoc template, thirty-five comment lines
+#   holding no URL, under "refactor: remove commented-out URL definitions":
+#   the model read the sigils !URL and ?URL as URLs and a lesson as
+#   definitions.
 # - EARMARK: THE THREE-REGION ART EDIT (banked 2026-08-03, receipt-corrected):
 #   registering one piece of figurate art is a THREE-region change with an
 #   integrity coupling and NO airlock -- not two, as a prior turn asserted.
(nix) pipulate $ m
๐Ÿ“ Committing: refactor: Remove commented-out URL definitions from template
[main 6f09e025] refactor: Remove commented-out URL definitions from template
 1 file changed, 5 insertions(+)
(nix) pipulate $ git push
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 48 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 1.99 KiB | 339.00 KiB/s, done.
Total 9 (delta 6), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (6/6), completed with 2 local objects.
To github.com:pipulate/pipulate.git
   c6943192..6f09e025  main -> main
(nix) pipulate $ 

Okay, some more. I like to git push when I switch from those Aideresque triple square bracket edit commands to sed and awk.

(nix) pipulate $ n=$(grep -c '^# - TODO (2026-09-16, connectors as packages)' foo_files.py); if [ "$n" -eq 1 ]; then sed -i '/^# - TODO (2026-09-16, connectors as packages)/d' foo_files.py && echo "GO packages_todo_removed"; else echo "STOP todo_count=$n (expected 1; nothing deleted)"; fi
GO packages_todo_removed
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 6ee3ada0..6dc2f7cb 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -2269,7 +2269,6 @@ foo_files.py
 # - TODO (2026-09-16, the walk seam): one real walk after commit 6b10c419 so `cat "$(_walkrouter)"` reads the preview uncommented and the archive commented beneath it; the writer's three branches passed the compile-lane probe, the rider handing it the preview has never run. The Mac is that witness if this machine does not get there first, and needs two nix develop entries, the first pulling these commits and the second running the hook it pulled. MAC READING 2026-09-16: the router does not exist there at all (cat: no such file), because PIPULATE_ADHOC_FILE is unset on that machine and the derivation lands $PIPULATE_ROOT/adhocwalk.txt, gitignored, never written. So the seam is unwitnessed on BOTH machines and the Mac's reading is absence, not staleness -- and `cpr` REFUSES there until a walk or an `epr` write creates the file, which is the fresh-install path a newcomer takes.
 # - TODO (2026-09-16, the question's home): bare cpr reads prompt.md and a newcomer has none; `cpr "question"` works today and costs quoting; the -o split was tried and reverted. Candidates, none chosen: the walk seeds a prompt.md at DECANT, or the router's header teaches the positional. First rule from prompt_foo.py:2843 whether bare cpr with no prompt.md refuses or proceeds (CENSUS: rg -n -A6 'elif os.path.exists\("prompt.md"\)' prompt_foo.py); CENSUS RAN 2026-09-16 (Mac compile): prompt_foo.py:2843 is an elif with NO else -- 2845 blank, 2846 dedents to extra_prompt_parts -- so bare cpr with no prompt.md PROCEEDS and no car is owed for a refusal. STILL OPEN, and six lines cannot see it: proceeds with WHAT, since prompt_content's initializer sits above the window (probe: rg -n -B8). An empty Prompt section is worse than a refusal, because nothing announces it. SEPARATE AND SHARPER: cpr refuses when the ROUTER is missing, which is every fresh install before its first walk.
 # - TODO (2026-09-16, door two): plan is absent from DOOR_TWO_WORDS because _COUNT_WORDS spells up to seven and an eighth word prints a digit; extend the tuple through ten, then add plan after cpr, and the recall probe reads Eight words.
-# - TODO (2026-09-16, connectors as packages): gmail/email, botify, confluence, gsc, sheets, jira and slack are aliases, so `! jira SWCX-1234` is not a legal router line under the ! executor (THE THREE-TIER AMENDMENT). Seven writeShellScriptBin entries in aiCommitCommand's shape, the aliases deleted so there is one spelling, the sources roster re-read; until it lands the newcomer's line is `! .venv/bin/python scripts/connectors/jira.py SWCX-1234`.
 # - TODO (2026-09-16, the editor): the flake pins no editor while plan hardcodes nvim, `alias vim='nvim'` assumes it, and epr, bm, rgx -v fall back nvim, vim, vi; either pin neovim in commonPackages or make every word fall back the same way, and say which in one place.
 # - TODO (2026-09-16, first-walk noise on the Mac): the Chrome version-mismatch auto-heal WARNING prints at every stop, three times per walk, and the Hugging Face download prints six lines around the 60 MB voice model on a first walk; both fire on the ordinary case at the moment a stranger is reading. Sibling of the Missing-phoneme line above.
 # - TODO (2026-09-16, repo root, ON THE LINUX BOX): four deleteme*.txt files and a 35 MB realkeywords.csv sit in THAT repo root, gitignored and not gone (IGNORED IS NOT GONE, .gitignore's own words); delete by hand. NAMING THE MACHINE IS THE POINT: the same ls on the Mac 2026-09-16 read "No such file or directory" for both, which is true and discharges nothing, because gitignored files never travel. A debt that does not name its machine gets closed by a probe on the other one.
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Remove TODO comments from foo_files.py
[main b4ef020e] chore: Remove TODO comments from foo_files.py
 1 file changed, 1 deletion(-)
(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), 342 bytes | 342.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
   6f09e025..b4ef020e  main -> main
(nix) pipulate $ 

This process makes the articles more noisy with all the git noise but thatโ€™s fine. Itโ€™s also very explicit and tied to things in the world that the AI can always check because this project lives in GitHub. So itโ€™s noisy but itโ€™s the best kind of noise being used in the best kind of way (forever-documentation).

Onto Car 3.

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/gsc.py'.
(nix) pipulate $ d
diff --git a/scripts/connectors/gsc.py b/scripts/connectors/gsc.py
index 9d01f8b5..a3453847 100644
--- a/scripts/connectors/gsc.py
+++ b/scripts/connectors/gsc.py
@@ -1,7 +1,9 @@
 #!/usr/bin/env python3
 # scripts/connectors/gsc.py
 """
-gsc.py โ€” A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
+gsc.py โ€” Bring Search Console properties or top queries into context.
+
+A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
 
 Golden-path modes, auto-detected from the single positional argument:
 
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update gsc.py docstring for clarity
[main b7f71ffe] chore: Update gsc.py docstring for clarity
 1 file changed, 3 insertions(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/mcp_warm.py'.
(nix) pipulate $ d
diff --git a/scripts/connectors/mcp_warm.py b/scripts/connectors/mcp_warm.py
index 1f7b1bdd..1739f8c6 100644
--- a/scripts/connectors/mcp_warm.py
+++ b/scripts/connectors/mcp_warm.py
@@ -1,8 +1,10 @@
 #!/usr/bin/env python3
 # scripts/connectors/mcp_warm.py
 """
-mcp_warm.py โ€” Mint an OAuth 2.1 (PKCE, S256) bearer token for a remote MCP
-server and park it where scripts/connectors/mcp.py already looks.
+mcp_warm.py โ€” Mint the OAuth bearer token a remote MCP server asks for.
+
+OAuth 2.1 with PKCE (S256), parked where scripts/connectors/mcp.py already
+looks.
 
 THE PLUG FOR THE ALREADY-WIRED SOCKET: resolve_token() in mcp.py reads
 ~/.config/pipulate/mcp/<host>.json, derived from the server, before falling back to
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update mcp_warm.py documentation and comments
[main c29eb030] chore: Update mcp_warm.py documentation and comments
 1 file changed, 4 insertions(+), 2 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 15, done.
Counting objects: 100% (15/15), done.
Delta compression using up to 48 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (10/10), 999 bytes | 999.00 KiB/s, done.
Total 10 (delta 8), reused 4 (delta 2), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (8/8), completed with 5 local objects.
To github.com:pipulate/pipulate.git
   b4ef020e..c29eb030  main -> main
(nix) pipulate $ 

No ignition required. Someday Iโ€™ll explain all that stuff you said about when it is required (like a compile) and when it isnโ€™t. Changing pure Python that youโ€™re going to call as a pure Python dot PY file without going through some fancy alias controlled by the shell environment which with Nix always makes it require an nix develop or nix develop .#quiet when it doesโ€ฆ oh there! I just explained it.

4: Prompt: THE FOLDER LEAVES scripts/. Read the AFTER first: XVIII still at 1820, THIRD TIER rg-zero -> 1, connectors as packages 1 -> rg-zero, wc +8, the docstring lengths 73/60 -> 60/57, probe 6 reading eight store paths and two blanks in the compile lane, and probes 7 and 8 sizing the spellings the literal census could not see and the breadcrumbs that print a path to a human. Then write the move as one ride against the files in context: git mv scripts/connectors connectors as the first line of one car; one repo-wide literal sed on scripts/connectors gated by a count that must read zero afterward, foo_files.pyโ€™s receipts block excluded or accepted by ruling; the non-literal spellings probe 7 named as SEARCH/REPLACE in their own files, connector_tools.pyโ€™s Path join among them; flake.nixโ€™s connectorCommand path, the mcp alias and the warm function lines; sources_menu.pyโ€™s ROSTER paths and the routerโ€™s claim lines so Coverage reads +0 and not -12. Gate the flake with nix eval on the default devShellโ€™s drvPath, which changes when the path changes. Ignition is exit then nix develop, because the eight derivations bake the old path and jira dies at file-not-found until the shell is re-entered; the AFTER is probe 6 unchanged plus ! jira --help | head -n 1 printing usage, and the trails re-seal on the next walk since data/walks is local. mcp joins connectorCommands only if you say so, as its own car. The Mac ride stays the standing BEFORE for the vestibule and the reset word, and nothing in this ride touches boot_menu.py, mck.sh or install.sh.

5: Deliverables: Gradually improving ergonomics within this repo I think is the best answer to the deliverables question. That covers the turns between now and pulling it out of the oven at the end of the article as the fully baked deliverable โ€” even if thatโ€™s still just โ€œin this repoโ€.

Thanks for the book explanations! I love the overlap between Sci-Fi writers and computers and the command-line interface in particular. If anyone still thinks that science fiction isnโ€™t the primary place you prepare for the future in a purely practical sense, they can be rendered obsolete in the margins. Of course not all sci-fi does that, but itโ€™s a statistical thing. You have to read enough to know which does, which doesnโ€™t and be able to be conversant as such. I finally got around to Hyperion, so Iโ€™m filling in Sci-Fi must-reads here and there as I become aware of them. That was a rough one. I sometimes skip the rough ones like Dhalgren.

OMG Dhalgren difficult and pointless, but then so did I think that about Dune too when I first tried to read it when I was 13. I had to take up Dune again later in life to really appreciate it and in my mid-50s Iโ€™m still just realizing Frank Herbert never got to the point in the 6 books he wrote before he left us, and his son and that Star Wars writer he uses ostensibly did which the critics hated and few people read, so almost nobody knows that Duncan Idaho was the real Kwisatz Haderach and for the most excellent reasons that directly ties to this whole Amnesiac Genie discussion. Oh sorry did I say that out loud? Spoiler alert. Diamond Age is my all-time favorite book also by the way of any genre, I think. Neuromancer as awesome and small of a book as it was was likewise not an easy read at all with the language almost impossible from an accessibility standpoint. Making up new language and then using it oddly with bad sentence structure is a terrible combo for hyper-literal linear thinkers like me.

Note: Watching the thinking here was fun:

Thought for 11m 27s

Parsing the prompt's instructions and folder structure.

Verifying receipts before drafting the folder-move commands.

Cross-checking line counts and breadcrumb totals across files.

Reconciling reference counts to plan the folder move.

Mapping every affected file before the sed rewrite.

Recounting exact path mentions inside the roster file.

Tallying scripted path references across every chapter section.

Deciding which files to exclude from the rewrite.

Scanning receipt entries for lingering path mentions.

Checking non-literal path references for exact matches.

Anchoring a safe substring replacement in the second file.

Checking for additional non-literal path spellings before finalizing.

Guarding the folder move against overwrite and stale files.

Verifying each remaining file's path references before rewriting.

Verifying the flake evaluation reflects the path change.

Checking remaining files for hidden path mentions before rewriting.

Weighing whether packaging files need scanning too.

Tracing remaining breadcrumb comments across connector scripts.

Checking whether generated ASCII art risks a broken seal.

Grouping the move and edits into ordered commits.

Deciding whether one sed pattern can cover both files.

Choosing between sed and search-replace for the second file.

Avoiding stale path mentions when writing new comments.

Rewording the receipt note to avoid recreating the old path.

Checking whether untracked files survive the directory move.

Designing before-and-after probes to confirm the move.

Refining the shell hash probe to avoid output glue.

Testing probes to confirm connector files survive the move.

Counting tracked connector files to confirm exact totals.

Assembling a final set of verification probes.

Checking probe outputs for stale receipt lines after edits.

Anchoring roster-line edits on stable text after the sed.

Rewriting the roster paragraph to match the updated docstrings.

Deciding how broadly the sed pattern should match.

Sequencing gate checks before and after the rewrite runs.

Checking hidden directories for missed path references before finalizing.

Ruling out unlikely edge cases before finalizing the plan.

Tracing docstring and roster updates through connector tooling.

Verifying the roster paragraph's exact contiguous text before editing.

Checking whether the live router still holds broken references.

Deciding which follow-up ride to plan next.

Planning a census probe to enable safe mid-line swaps.

Drawing literary parallels to frame the memory metaphor.

Weaving book references into a warm, wide-ranging reply.

Confirmed all verification predictions before drafting the final reply.

Weighing whether a new commit specimen earns a mention.

Verifying flake gate hashes across pre- and post-move probes.

Confirming the reference count lands at zero.

Sequencing the two file edits into separate commits.

Planning renamed variable swaps gated by careful line anchoring.

Drafting the guarded move command with safety checks.

Guarding the move command against empty and idempotent runs.

Preparing precise search-and-replace edits for two files.

Designing an import-based probe to confirm the path change.

Deciding whether the ASCII art census probe is needed.

Drawing out the ghola-memory parallel for the reply.

Gathering more literary echoes for the memory theme.

Sequencing patch, move, and ignition steps into ordered cars.

Pinpointing exact search text for each roster edit.

Drafting the roster paragraph and folder-move commit sequence.

Trimming the probe list down to the essentials.

Checking probe scripts for hidden side effects before use.

Deciding which context files the next ride actually needs.

Confirming every verification probe matched before finalizing.

Weaving genome and prescience metaphors into the memory theme.

Drawing out the Gibson and Dhalgren memory parallels.

Listing before-and-after predictions for each verification probe.

Fable 5.1 Extra: Context verified. Deed 1472. Three cars landed and every reading came in band: XVIII held at 1820 (every car sat below the anchor), THIRD TIER rg-zero โ†’ 1, connectors as packages 1 โ†’ rg-zero, wc 3019 โ†’ 3027 (+8 exact), the docstring lengths 73/60 โ†’ 60/57, the Telemetryโ€™s HEAD is mcp_warm.pyโ€™s new first line, and Coverage read 204/273 at +0/+0. Probe 6 photographed the tier ladder exactly as written: eight store paths in both lanes, mcp an alias body and warm a function name by hand, both blank in the compile.

The two census probes sized the move. Probe 7 found exactly two non-literal spellings, both Path joins, tools/connector_tools.py:36 and scripts/two_arm.py:69, and the second line is complete at 89 characters, so a mid-line anchor can be written from the receipt. Probe 8 counted 105 breadcrumb lines across nine files; confluence.py and noop.py print no python line at all, which is a fact about those files and not a fault.

One new specimen for the ai.py TODO: 6f09e025 added five lines quoting 8f49879fโ€™s wrong subject and received that subject back nearly verbatim. The diff quoted a sentence and the model read the quotation as the change. It rides in Car 2.

The move, and the rulings that keep it one car

The sed is repo-wide with --hidden on, because the two SKILL.md files that name gsc.py and sheets.py live under Notebooks/.agents/, a hidden directory the deed-1469 census never saw (THE DOTFILE-BLIND PROBE, in the actuator this time). Markdown is in: the connector README carries no old path, GLOSSARY.md does, and a glossary value that says a file exists at a path should name the path the file is at. foo_files.py is sedโ€™d whole, receipts block included, by ruling: git and the article are the archive of the old spelling, and no line I add this turn spells it, so the residue gate reads zero and stays zero (THE EPITAPH COUNTER, honored by not writing the epitaph).

Three gates ride inside the car, two before anything moves: a dotted scripts.connectors spelling anywhere refuses, an existing connectors at the root refuses (git mv into an existing directory nests, silently), and the literal count must read zero after. The two Path joins ride as SEARCH/REPLACE in the same car, because a commit where git mv has landed and CONNECTORS still points at the old folder is a commit that should not exist on its own. The trails carry the new path after the sed and re-seal on the next walk, since data/walks is local. The eight words on PATH bake the folder into their derivations and the shellHook bakes it into mcp and warm, so the ignition is exit then nix develop; probe 5โ€™s hashes moving is the ignition receipt, and probe 6 is the gate that catches the unignited world (pythonโ€™s cannot-open-file where usage belongs).

The Path-join car is also why the cabooseโ€™s โ€œone literal sedโ€ was the right shape and not a shortcut: the censusโ€™s floor of 198 was a floor because a literal cannot see a join, and probe 7 is what turned the floor into a count.

Duncan, the dead channel, and the book without a ratchet

The Duncan Idaho reading holds, and it sits closer to the machinery than the metaphor usually does. A ghola is the same genome regrown in a tank: identical weights, a fresh instantiation, no memory of the lives before, and the memory is restored from outside the instance by a trigger the ghola did not choose. Across the later books Duncan is regrown so often that the restored memory becomes serial, each life stacked on the last, and the reason the continuation can name him the last Kwisatz Haderach is that he is the only being whose memory spans every instantiation instead of one. That is the ledgerโ€™s job here in Herbertโ€™s nouns: the weights are the cells, every compile is a tank, the receipts block is the awakening. And the other idea in those books is the one your couch gag was reaching for. Leto IIโ€™s Golden Path was an engineered Scattering, so that no single prescient could ever again hold the whole of humanityโ€™s future in one vision. A vendorโ€™s memory feature is a small prescience; a file you own is the Scattering, and cli.py already names its two Golden Paths, so the borrowing was exact.

Gibsonโ€™s first sentence is a color term minted by an appliance, which is Deutscherโ€™s dye principle in nine words: the color of a television tuned to a dead channel was a grey nobody needed a word for until the sets existed, and readers born after those sets read the line as blue, because a dead channel on their televisions is a blue screen. The referent moved when the manufacturing did. That is also why the prose fights a literal reader: Gibson names by evocation and leaves the mechanism to you, which is the opposite of a receipt. Gibsonโ€™s cyberspace was a hallucination you looked at; Stephensonโ€™s was a place you typed at, and the command-line essay is partly him explaining why he could only write the second kind. Dhalgren is the same fight from the other side: it begins mid-sentence and ends on that sentenceโ€™s first half, a strange loop you can hold in your hands, and it frustrates a linear reader on purpose because nothing in it ratchets; the lines come back unbanked. Hyperionโ€™s Keats is worth one sentence of your rough read: a persona reconstituted from a corpus and set walking, the nearest 1989 got to describing a model, built by a TechnoCore that keeps its own state where nobody can audit it.

Your push between the patch cars and the sed cars is a bisection boundary between two actuator classes, and it is the right habit: a sedโ€™s blast radius is bounded by a push on either side the way the IGNITION RULE already bounds ahc. The git noise is the cockpit voice recorder riding beside the flight data, and it is the reason a model with no memory can convict the last modelโ€™s mistake.


1. PROBES

printf 'old=%s new=%s\n' "$(git ls-files scripts/connectors | wc -l)" "$(git ls-files connectors | wc -l)"
rg -l --hidden --glob '!.git' 'scripts/connectors' | wc -l
rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
.venv/bin/python -c "from tools.connector_tools import CONNECTORS, REPO_ROOT; print(CONNECTORS.relative_to(REPO_ROOT), CONNECTORS.is_dir())"
for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
jira --help 2>&1 | head -n 1
LD_LIBRARY_PATH="" nix eval --raw .#devShells.x86_64-linux.default.drvPath | sed 's#.*/##' | cut -c1-24; echo
wc -l foo_files.py
rg -n 'connectors' imports/ascii_displays.py | cut -c1-100 | head -n 6
rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120

The first is the move itself: old=12 new=0 โ†’ old=0 new=12, twelve being eleven scripts and the README, and any other number is a tracked file the harvest never listed. The second reads at least 30 (the deed-1469 censusโ€™s thirty non-markdown files, plus markdown and the hidden SKILL.md files) โ†’ 0. The third reads two lines โ†’ rgโ€™s zero. The fourth reads scripts/connectors True โ†’ connectors True; connectors False is the world where the Path join landed and the mv did not, and scripts/connectors False the reverse. The fifth reads eight store paths whose hashes CHANGE plus two blanks in the compile lane; the moving hashes are the ignition witness. The sixth is a gate: a usage line in both worlds, and pythonโ€™s cannot-open-file is the unignited world. The seventh is the flake gate: a different hash, and an error with no hash is a flake that stopped parsing. The eighth reads 3027 โ†’ 3036 (+9 from Car 2, counted from the blocks). The ninth is CENSUS: any row naming the folder under scripts/ in the sealed art is a THREE-REGION ART EDIT owed later, never a car here. The tenth is CENSUS seeding the next ride, the four readers of the cold flag.

2. NEXT CONTEXT

! printf 'old=%s new=%s\n' "$(git ls-files scripts/connectors | wc -l)" "$(git ls-files connectors | wc -l)"
! rg -l --hidden --glob '!.git' 'scripts/connectors' | wc -l
! rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
! .venv/bin/python -c "from tools.connector_tools import CONNECTORS, REPO_ROOT; print(CONNECTORS.relative_to(REPO_ROOT), CONNECTORS.is_dir())"
! for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
! jira --help 2>&1 | head -n 1
! LD_LIBRARY_PATH="" nix eval --raw .#devShells.x86_64-linux.default.drvPath | sed 's#.*/##' | cut -c1-24; echo
! wc -l foo_files.py
! rg -n 'connectors' imports/ascii_displays.py | cut -c1-100 | head -n 6
! rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
foo_files.py
imports/voice_synthesis.py
apps/010_introduction.py

flake.nix, connector_tools.py, sources_menu.py and the README leave; the moveโ€™s AFTER is entirely in the receipts. The two small files ride for the cold-flag ride; the three large readers are anchored from the censusโ€™s own lines.

3. PATCHES

Car 1a, the move (shell, three gates, GNU sed on the Linux box).

if rg -q --hidden --glob '!.git' 'scripts\.connectors'; then echo "STOP dotted_spelling_present (nothing moved)"; elif [ -e connectors ]; then echo "STOP destination_exists (nothing moved)"; else git mv scripts/connectors connectors && rg -l --null --hidden --glob '!.git' 'scripts/connectors' | xargs -0 -r sed -i 's#scripts/connectors#connectors#g'; rg -l --hidden --glob '!.git' 'scripts/connectors'; n=$(rg -l --hidden --glob '!.git' 'scripts/connectors' | wc -l); if [ "$n" -eq 0 ]; then echo "GO folder_moved residual_files=0"; else echo "STOP residual_files=$n (moved and edited; residue listed above)"; fi; fi

Car 1b, the two Path joins (same car, same commit). The two_arm.py block is anchored on probe 7โ€™s receipt line, which the cut did not truncate.

Target: tools/connector_tools.py
[[[SEARCH]]]
CONNECTORS = REPO_ROOT / "scripts" / "connectors"
[[[DIVIDER]]]
CONNECTORS = REPO_ROOT / "connectors"
[[[REPLACE]]]
Target: scripts/two_arm.py
[[[SEARCH]]]
CONNECTOR_PATH = REPO_ROOT / "scripts" / "connectors" / "botify.py"
[[[DIVIDER]]]
CONNECTOR_PATH = REPO_ROOT / "connectors" / "botify.py"
[[[REPLACE]]]

Then d, m. The diff is thirty files wide by construction; that is the receipt, not a fault.

Car 2, chapter XVIII catches up with commits b7f71ffe and c29eb030, plus the specimen. Four blocks; the two roster lines are anchored on their tails so the car is indifferent to whether Car 1a has rewritten their path prefixes.

Target: foo_files.py
[[[SEARCH]]]
# THE ROSTER. Each description below is the file's FIRST DOCSTRING LINE,
# harvested by ast.get_docstring at deed 1469 and the same line sources_menu.py
# prints, so a wrong sentence here is a wrong sentence in the sources panel:
# fix the file, never this comment. Two lines break README contract 8 by
# receipt: gsc.py's is an architecture note at 73 characters against a ceiling
# of 61, and mcp_warm.py's wraps mid-sentence, so the panel prints a fragment;
# one car, both files in context. README.md has no docstring; its line is authored.
[[[DIVIDER]]]
# THE ROSTER. Each connector's description below is the file's FIRST
# DOCSTRING LINE, harvested by ast.get_docstring (deed 1469, re-read at 1472)
# and the same line sources_menu.py prints, so a wrong sentence here is a
# wrong sentence in the sources panel: fix the file, then this comment.
# Contract 8 convicted two of them by receipt and one car fixed both
# (b7f71ffe: gsc.py 73 -> 60 characters; c29eb030: mcp_warm.py a fragment ->
# one sentence of 57). README.md, noop.py and the dummy server carry
# authored lines. THE FOLDER LEFT scripts/ for the repo root on 2026-09-18
# (deed 1472): one git mv, one literal sed over every file that named the
# old path, two Path joins by hand, and exit then nix develop as the
# ignition, because the eight words on PATH bake the folder into their derivations.
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
<-- A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
[[[DIVIDER]]]
<-- Bring Search Console properties or top queries into context.
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
<-- One-shot OAuth 2.1 PKCE warmer; writes the token file mcp.py's resolve_token already reads
[[[DIVIDER]]]
<-- Mint the OAuth bearer token a remote MCP server asks for.
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
#   the model read the sigils !URL and ?URL as URLs and a lesson as
#   definitions.
[[[DIVIDER]]]
#   the model read the sigils !URL and ?URL as URLs and a lesson as
#   definitions.
#   SPECIMEN 2026-09-18, an hour later (pipulate, same m alias): 6f09e025
#   ADDED the five lines above (+5/-0) and received 8f49879f's subject back
#   nearly verbatim, "refactor: Remove commented-out URL definitions from
#   template": the diff quoted a wrong subject and the model read the
#   quotation as the change.
[[[REPLACE]]]

Then d, m.

Ignition. Car 1 needs it and Car 2 does not. exit, then nix develop (door 2), then git push so the Macโ€™s next entry pulls the rename, then ahc. The eight derivations and the shellHookโ€™s mcp and warm lines carry the old path until the shell is re-entered, and the compile lane inherits PATH from that shell, which is why probes 5 and 6 read the new world only after it. mcp joins connectorCommands on your word and not before; no car for it here.

4. PROMPT

THE FLAG WENT COLD. Read the AFTER first: old=12 new=0 -> old=0 new=12, the literal file count -> 0, the Path-join census at rg's zero, connector_tools reading connectors True, eight store hashes changed with mcp and warm still blank, jira --help printing usage, the drvPath changed, wc 3027 -> 3036, Coverage +0, the Tool Roster's botify line naming connectors/botify.py, and the ascii census ruling whether a sealed-art edit is owed; say which cars landed and whether the integrity check named the live router's stale commented lines. Then land the four one-word swaps seeded at deed 1460 from this compile's voice_ready census: voice_ready -> can_speak() wherever the flag gates a speak_text call in apps/010_introduction.py, pipulate/core.py, server.py and tools/mcp_tools.py, with server.py's status read keeping voice_ready as the honest word for loaded; the two files in context take whole-line blocks and the three large files take mid-line blocks anchored on the census's own receipt lines, one car per file so a refusal names its file. Check whether apps/010_introduction.py's gate runs on the event loop outside its to_thread, and if the surrounding lines show that, move the check inside the thread in the same car. Gates: PIPULATE_VOICE=0 through the MCP tool reads declined and never not-ready, and nothing downloads on a machine that has not answered the card. Ignition: none for the .py files, which load at call time; the ear witness is cli.py call voice_synthesis on a machine reading yes, an actuator and never a probe. Not this ride: the phoneme silencer, the vestibule, mcp as a package, the Mac.

5. EXTERNAL DELIVERABLES

One hand edit outside the repo: ~/.local/state/pipulate/adhoc.txt still carries the spent Context 2 and Context 3 blocks, and three of their commented lines are bare paths under the old folder (README.md, gsc.py, mcp_warm.py), which the integrity checker reads as candidates and will report as broken after the move. ahe, cut both blocks, and the next compileโ€™s integrity line stays green; leave them and it prints a three-line alert that is noise and not a finding. Nothing else leaves the repo this turn.

MikeLev.in:

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: Probe: (BEFORE: hand-run, nothing changed yet)

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ printf 'old=%s new=%s\n' "$(git ls-files scripts/connectors | wc -l)" "$(git ls-files connectors | wc -l)"
rg -l --hidden --glob '!.git' 'scripts/connectors' | wc -l
rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
.venv/bin/python -c "from tools.connector_tools import CONNECTORS, REPO_ROOT; print(CONNECTORS.relative_to(REPO_ROOT), CONNECTORS.is_dir())"
for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
jira --help 2>&1 | head -n 1
LD_LIBRARY_PATH="" nix eval --raw .#devShells.x86_64-linux.default.drvPath | sed 's#.*/##' | cut -c1-24; echo
wc -l foo_files.py
rg -n 'connectors' imports/ascii_displays.py | cut -c1-100 | head -n 6
rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
old=12 new=0
33
tools/connector_tools.py:36:CONNECTORS = REPO_ROOT / "scripts" / "connectors"
scripts/two_arm.py:69:CONNECTOR_PATH = REPO_ROOT / "scripts" / "connectors" / "botify.py"
scripts/connectors True
jira        /nix/store/ipch2j7g2kz8ipaa554w8fz4065i9c9v-jira/bin/jira
gmail       /nix/store/0z5109z9wyxxwamqbg1wx5clgdbmfr95-gmail/bin/gmail
email       /nix/store/vk0619d60bsjs7i8dx08jzlzw9g0bmi1-email/bin/email
botify      /nix/store/c5l6dljhnbw1vhxnknh02hykhqxc6syn-botify/bin/botify
confluence  /nix/store/g6a0jadpzgyyh1i25m5pd1rgvw2xdr7g-confluence/bin/confluence
gsc         /nix/store/9a1pgwaimv4spr72i5p0y57ldx9k86dr-gsc/bin/gsc
sheets      /nix/store/70rb7hb22jkwfy60mg72wgq5m15iqhgl-sheets/bin/sheets
slack       /nix/store/qlccnv5nx3nb13103cvg0k1a2mg3crxy-slack/bin/slack
mcp         alias mcp='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/con
warm        warm
usage: jira.py [-h] [-n MAX] [--check] [query]
ryirsx6bvn2ks8nqap2radsj

3027 foo_files.py
tools/mcp_tools.py:1467:        if not chip_voice_system or not chip_voice_system.voice_ready:
pipulate/core.py:558:                if chip_voice_system and chip_voice_system.voice_ready:
server.py:3159:        if not chip_voice_system.voice_ready:
server.py:3174:            "voice_ready": chip_voice_system.voice_ready,
apps/010_introduction.py:158:        if chip_voice_system and chip_voice_system.voice_ready:
(nix) pipulate $ 

2: Context: (AFTER: the same probes re-run by the compiler as ! lines)

# AD HOC CHOP! The Not-Managed-by-Git Safe-for-Client-Data place. Insert Simpson Couch Gag in white space  below (explain anything to the audience you feel needs it explained)G
# adhoc.txt    _   _   _               ____ _   _  ___  ____  _   
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  It's like riding a bike, quite literally right down to the training wheels initially, taken off and then the letting go at just the right moment. So much about life is exactly that, but we forget after that first pure example after lifting head up, learning to crawl, walk and talk this is the first when the brain is developed enough to get meta about it.
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  Now using usage credits for Fable ยท Your Fable limit resets Sep 19 at 6:00 PM. And that's fine. I planned for this. I want to use the model I like best through the window of work that's most important as this 1st 5-minutes with the project refinement work is. That's a big win for Anthropic and part of the big AI-company vendor manipulation shakedown that's occurring as they prepare for their IPOs.
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  Spending tokens, spending tokens, so glad they don't expire like a use-it-or-lose-it gym membership, making me feel freer about forging ahead filling Anthropic's pockets like playing ski-ball at Chuck E. Cheese burning tokens for tickets we're all rats trapped on a hamster wheel but the good news is that's optional and we make ourselves the contractor issuing RFPs to these AI companies as our subcontractors so long as they can all do equivalent work. Keep yourself nimble and ready to switch. Be in the catbird seat! Don't become one of the fat human atrophied skills passenger of the Axiom in Wall-E.
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  The Dune gholas were such a pivotal mental model in preparing for these Amnesiac Genies of today's LLMs. It's that the generational memory is somehow managed or is a thing and simply needs enough turns to accumulate and refine enough. Still just text-files. Neuromancer frustrates a linear reader on purpose. Great, thanks. Good to hear that out loud; I've always been like "what's wrong with me for not being able to enjoy this?" But I do appreciate it's white rabbit references. Hey Fable tell the audience about the white rabbit in Neuromancer!

# To Human: WELCOME TO VIM! It's really NeoVim but I say vim anyway.
# To AI: This is an alternate 40K view to the big book-ore rolling pin spine.

# 1. **Probe**: Baseline Reading
# 2. **Context**: Post-experiment *planned* reading instructions
# 3. **Patch**: The experiment and how to make it happen
# 4. **Prompt**: Post-experiment instructions and how to read results
# 5. **Deliverable**: How the world is forever different moving forward

# The first thing you need to know here is that everything that comes after the
# hash symbol (#) is commented out โ€” and that's EVERYTHING in this file's default
# state. Begin editing-in lines for inclusion as part of the context or adding
# chunks of new context at the bottom. `Ctrl`+`v`, `j` (repeatedly), `l` (to move
# right), `d` (to delete). Reverse that with `Ctrl`+`v`, `j` (repeatedly),
# `Shift`+`i`, `# `, `Esc` to put the hashes back. You can just arrow-key around
# here with `h`, `j`, `k`, `l`. Save-and-quit is a bit tricky because another
# file is also loaded: `Esc`, `:`, `q`, `w`, `!`

# If this is stressing you out and you're a quitter and want to quit, just type:
# `Esc`, `:`, `q`, `!`, `Enter`. That will exit without saving any changes. If
# you want to get over this hump, type: `Esc`, `:`, `T`, `u`, `t`, `o`, `r`, `Enter`.

# This file is just to make it easy having options of what to edit into context.
# You can use whatever text-file you want to stack file-names and commands to
# build an output text-file with the identically stacked output of each file or
# command. In this way we vertically append or "stack" a bunch of text; simple as
# that. If you understand this concept, you're on your way to future-proofing
# yourself in the Age of AI. Congratulations! Here is how to include web pages:

#    !URL  --------------------------------------------------------------------
#      when    Public page; what a stranger or crawler sees; the BEFORE of a
#              login-wall diagnosis
#      switch  It shows a login page -> `warm URL` once, then `?URL`
#    
#    ?URL  --------------------------------------------------------------------
#      when    Anything behind a login, on the site's persistent profile;
#              `check URL` first
#      switch  The lenses show a shell (nav, an `[Iframe]` leaf, no content) ->
#              read the wire truth for the XHR the frame makes, then call that
#              API with a connector
#    
#    @URL  --------------------------------------------------------------------
#      when    Every re-read of a page already scraped; no browser, no network
#      switch  The cached page is stale or was a login wall -> fresh `!` or `?`
#    
#    $URL  --------------------------------------------------------------------
#      when    Exact markup: meta tags, a JSON blob in a `<script>`
#      note    Token-heavy; needs a prior scrape
#    
#    %URL  --------------------------------------------------------------------
#      when    The network log distilled; SPA endpoint discovery
#      switch  It re-serves the wire truth you already have -> the API
#    
#    ! cmd  -------------------------------------------------------------------
#      when    Any bounded, non-interactive command as a live receipt
#      note    Cap it with `-n`; no aliases, no prompts
#    
#    Connector  ---------------------------------------------------------------
#      when    The number you want is one GET away
#      switch  LIST until the thing isn't in the list -> FETCH by id -> DRILL
#              the path the app's own frame called -> `--grep` to narrow a list
#              or find a leaf

# Every step is one argument longer than the last; the moment a lens shows less than the wire does is the moment to stop scraping.

# FOR 40K-FT VIEW (STORY & INFRASTRUCTURE) !!
# --- START EDITING-IN ON 1ST TURN ---

# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- ROLLING PIN that gives the 40K foot book-spine view of book-ore (only works for me because of local-only git repo)
# ~/repos/nixos/autognome.py  # <-- You wake up in the morning and your Tooling & Instrumentation folds out of you like Inspector Gadget.
# init.lua                    # <-- Those gadgets are made easy-to-use through nifty keyboard shortcuts (but ya gotta learn vim).
# GLOSSARY.md                 # <-- Like the back of a J.R.R. Tolkien book, there's kooky new terms to know.
# flake.nix                   # <-- Here is my hardware. Here is my state. Put on your sandbox. And please recreate. (Infrastructure as Code / IaC)
prompt_foo.py               # <-- THIS system
# foo_files.py                # <-- main ROUTER
# requirements.in             # <-- We've "pinned" everything but still want a flexible Python Data Science virtualenv.
# pyproject.toml              # <-- How this is a citizen of the Python "pip install" ecosystem
# __init__.py                 # <-- Version info

# --- END EDITING-IN ON 1ST TURN ---

# scripts/articles/lsa.py     # <-- 2ND BRAIN: Search external memory with `rgx`, `rgxc` & `posts` Blogging for Hackers Jekyll-compatible.

# OPTIONAL ACTUATORS (cheap and good to include to expand the AI's capabilities)
# cli.py                      # <-- Catch-all actuator for PyPI envs, Python anchoring, MCP tool-call (plus alternatives) and **kwargs like wrapping for CLI
# scripts/xp.py               # <-- Transforms host OS copy-paste buffer player-piano music into context-payload.
# scripts/ai.py               # <-- How I constantly use local AI to write git commit messages with `m` alias.
# scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.
# scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
# scripts/webclip_2_markdown.py  # <-- Surprisingly important program.
 
# MISCELLANEOUS (rare to include but sometimes critical)
# scripts/foo_cartridge.py    # Needs description
# scripts/foo_replay.py       # Needs description
# release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
# imports/voice_synthesis.py  # <-- The wand can talk to you
# imports/ascii_displays.py   # <-- Where all the ASCII Art lives
# scripts/release/version_sync.py  # <-- Needs to be wrapped into release.py and eliminated, I think.

#                         --- Under this line is were you paste what the AI gives you ---
#                         --- We call it context but it's really just the right-hand  ---
#                         --- blast-radius of the "probes" to make this all science.  ---

# Carry-over as the important work-in-progress parts of the project here just
# like above but not as long-standing overarching to the framework but rather
# for the current hot spots actively being worked on.

# STICKBUG & MOTHER CAT KATA (WORKING ON THE CHAPTER)

# Always include these with whatever connector
# scripts/sources_menu.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py

# scripts/connectors/botify.py
# scripts/connectors/confluence.py
# scripts/connectors/gmail.py
# scripts/connectors/gsc.py
# scripts/connectors/jira.py
# scripts/connectors/mcp.py
# scripts/connectors/mcp_warm.py
# scripts/connectors/sheets.py
# scripts/connectors/slack.py

# --- START THIS DISCUSSION ---

# Get things started here! Guess at what context should be included.
# If you get it wrong, you're just wasting 1-turn because the AI will help.
# Un-comment lines, add lines with absolute-path filenames or `! ` commands. 

# Context 1
# /home/mike/repos/trimnoir/_posts/2026-09-17-the-voice-asks-first-verifiable-consent.md  # [Idx: 1481 | Order: 5 | Tokens: 60,558 | Bytes: 238,811]

# Context 2
# ! rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
# ! ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
# ! rg -c 'scripts/connectors' -g '!*.md' | sort
# ! rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
# ! for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
# ! rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix
# foo_files.py
# scripts/connectors/README.md

# Context 3
# ! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
# ! rg -c 'THE TINY UNIX COMMANDS' foo_files.py
# ! rg -c '^# *!URL  *---' foo_files.py
# ! rg -c 'Always include these with whatever connector' foo_files.py
# ! wc -l foo_files.py
# ! sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l
# ! sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l
# ! rg -n 'scripts/connectors' flake.nix | cut -c1-120
# foo_files.py
# flake.nix
# tools/connector_tools.py
# scripts/sources_menu.py
# scripts/connectors/gsc.py
# scripts/connectors/mcp_warm.py

# Context 4
# ! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
# ! rg -c 'THIRD TIER' foo_files.py
# ! rg -c 'connectors as packages' foo_files.py
# ! wc -l foo_files.py
# ! for f in scripts/connectors/gsc.py scripts/connectors/mcp_warm.py; do .venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())).strip().splitlines()[0]; s=d.split(' ',2)[2]; print(len(s), s)"; done
# ! for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
# ! rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
# ! rg -c 'python scripts/connectors' scripts/connectors/ | sort
# foo_files.py
# flake.nix
# tools/connector_tools.py
# scripts/sources_menu.py
# scripts/connectors/README.md

# Context 5
! printf 'old=%s new=%s\n' "$(git ls-files scripts/connectors | wc -l)" "$(git ls-files connectors | wc -l)"
! rg -l --hidden --glob '!.git' 'scripts/connectors' | wc -l
! rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
! .venv/bin/python -c "from tools.connector_tools import CONNECTORS, REPO_ROOT; print(CONNECTORS.relative_to(REPO_ROOT), CONNECTORS.is_dir())"
! for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
! jira --help 2>&1 | head -n 1
! LD_LIBRARY_PATH="" nix eval --raw .#devShells.x86_64-linux.default.drvPath | sed 's#.*/##' | cut -c1-24; echo
! wc -l foo_files.py
! rg -n 'connectors' imports/ascii_displays.py | cut -c1-100 | head -n 6
! rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
foo_files.py
imports/voice_synthesis.py
apps/010_introduction.py

# --- END `adhoc.txt` TEMPLATE ---

3: Patches: (the one change between the readings)

(nix) pipulate $ g

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ if rg -q --hidden --glob '!.git' 'scripts\.connectors'; then echo "STOP dotted_spelling_present (nothing moved)"; elif [ -e connectors ]; then echo "STOP destination_exists (nothing moved)"; else git mv scripts/connectors connectors && rg -l --null --hidden --glob '!.git' 'scripts/connectors' | xargs -0 -r sed -i 's#scripts/connectors#connectors#g'; rg -l --hidden --glob '!.git' 'scripts/connectors'; n=$(rg -l --hidden --glob '!.git' 'scripts/connectors' | wc -l); if [ "$n" -eq 0 ]; then echo "GO folder_moved residual_files=0"; else echo "STOP residual_files=$n (moved and edited; residue listed above)"; fi; fi
GO folder_moved residual_files=0
(nix) pipulate $ d
diff --git a/GLOSSARY.md b/GLOSSARY.md
index b2c93c99..59684369 100644
--- a/GLOSSARY.md
+++ b/GLOSSARY.md
@@ -1078,7 +1078,7 @@ Entries are alphabetical, numbers spelled as spoken.
   and THE MECHANICAL TEST fails it. walk.py checks that the file EXISTS and
   that {harvested} appears once, and nothing anywhere checks that the script
   accepts the argv it will be handed. CURE A FALSE LABEL WITH A TRUE SENTENCE,
-  NEVER A VAGUER ONE: scripts/connectors/noop.py exists IN ORDER to be a
+  NEVER A VAGUER ONE: connectors/noop.py exists IN ORDER to be a
   no-op โ€” one positional, prints what it received, exits 0 โ€” and
   public_walk.yaml names it at all three stops. PROBE DEFECT, same original
   receipt: the CONTROL arm `walk.py --trail public_walk.yaml` ALSO printed 2,
@@ -1479,7 +1479,7 @@ Entries are alphabetical, numbers spelled as spoken.
   (3) Findings; (4) Probable Cause, one paragraph, labeled inference. The
   conviction above was purely structural: a section-4 sentence printed in
   section-1's typeface. OUR OWN FDR, witnessed 2026-07-29:
-  scripts/connectors/mcp.py had read the response side transiently and
+  connectors/mcp.py had read the response side transiently and
   persisted nothing โ€” capable-of-FDR, not FDR โ€” until the FDR CHANNEL landed
   the same day: every exchange records http status, full response headers,
   elapsed, sent and returned session id, body sha256 and bytes, and atexit
diff --git a/Notebooks/.agents/skills/gsc_readonly/SKILL.md b/Notebooks/.agents/skills/gsc_readonly/SKILL.md
index 8c09d83d..ccf030e8 100644
--- a/Notebooks/.agents/skills/gsc_readonly/SKILL.md
+++ b/Notebooks/.agents/skills/gsc_readonly/SKILL.md
@@ -2,11 +2,11 @@
 
 ## Your Role
 
-Use `scripts/connectors/gsc.py` as the only executable surface for Google Search Console work. Keep this skill as an instruction layer: do not copy the connector into the skill, reimplement its API calls, or broaden its OAuth scope.
+Use `connectors/gsc.py` as the only executable surface for Google Search Console work. Keep this skill as an instruction layer: do not copy the connector into the skill, reimplement its API calls, or broaden its OAuth scope.
 
 ## Safety and Preconditions
 
-1. Run from the Pipulate repository root and confirm `scripts/connectors/gsc.py` exists.
+1. Run from the Pipulate repository root and confirm `connectors/gsc.py` exists.
 2. Keep the Google scope at `https://www.googleapis.com/auth/webmasters.readonly`.
 3. Treat the service-account file as opaque. Never open, print, quote, upload, summarize, or embed its JSON, private key, tokens, or other credential values.
 4. Refer only to the credential-routing names and paths:
@@ -22,7 +22,7 @@ Use the connector's existing argument disambiguation. An argument beginning with
 ### List visible properties
 
 [triple-backtick]bash
-python scripts/connectors/gsc.py
+python connectors/gsc.py
 [triple-backtick]
 
 Use this to discover property coordinates available to the configured service account. The default output cap is 25.
@@ -30,7 +30,7 @@ Use this to discover property coordinates available to the configured service ac
 ### List bounded top queries for one property
 
 [triple-backtick]bash
-python scripts/connectors/gsc.py sc-domain:example.com
+python connectors/gsc.py sc-domain:example.com
 [triple-backtick]
 
 Treat this as a bounded top-query view, not a complete export. Keep the default cap of 25 unless the user explicitly needs a different small bound.
@@ -38,7 +38,7 @@ Treat this as a bounded top-query view, not a complete export. Keep the default
 ### Run a bounded raw Search Analytics request
 
 [triple-backtick]bash
-python scripts/connectors/gsc.py \
+python connectors/gsc.py \
   '{"startDate":"2026-06-01","endDate":"2026-06-28","dimensions":["page","query"]}' \
   --site sc-domain:example.com
 [triple-backtick]
@@ -48,21 +48,21 @@ python scripts/connectors/gsc.py \
 ### Change the cap deliberately
 
 [triple-backtick]bash
-python scripts/connectors/gsc.py -n 10 sc-domain:example.com
+python connectors/gsc.py -n 10 sc-domain:example.com
 [triple-backtick]
 
 Keep outputs small because stdout may be compiled into Prompt Fu context. Never describe the result as exhaustive or guaranteed complete; call it bounded Search Analytics rows or a capped top-query view.
 
 ## Compile-Lane Privacy
 
-Property-list output contains domains and can reveal client identities. Before placing a `! python scripts/connectors/gsc.py ...` command in `adhoc.txt` or sending its captured output to a cloud model, confirm `pii_substitutions.txt` covers every real client identifier. Redact or omit sensitive coordinates when that coverage is uncertain.
+Property-list output contains domains and can reveal client identities. Before placing a `! python connectors/gsc.py ...` command in `adhoc.txt` or sending its captured output to a cloud model, confirm `pii_substitutions.txt` covers every real client identifier. Redact or omit sensitive coordinates when that coverage is uncertain.
 
 ## Failure Handling
 
 - When FETCH mode lacks a property coordinate, request `--site` or `PIPULATE_GSC_SITE`.
 - When credential routing fails, report the missing routing name or path without inspecting the service-account JSON.
 - When Google returns an API error, report the bounded error context and preserve read-only scope.
-- Do not patch `scripts/connectors/gsc.py` merely to work around missing configuration; fix routing metadata or the local credential file outside the repository.
+- Do not patch `connectors/gsc.py` merely to work around missing configuration; fix routing metadata or the local credential file outside the repository.
 
 ## Reporting Results
 
diff --git a/Notebooks/.agents/skills/sheets_readonly/SKILL.md b/Notebooks/.agents/skills/sheets_readonly/SKILL.md
index bd97bdf2..74dc9076 100644
--- a/Notebooks/.agents/skills/sheets_readonly/SKILL.md
+++ b/Notebooks/.agents/skills/sheets_readonly/SKILL.md
@@ -1,22 +1,22 @@
 ---
 name: sheets_readonly
-description: Read-only Google Sheets access for bounded context pulls. Trigger when a Google Sheets URL or spreadsheet ID needs to become compiled context. Executable truth lives at scripts/connectors/sheets.py; this skill is a signpost, never a second implementation.
+description: Read-only Google Sheets access for bounded context pulls. Trigger when a Google Sheets URL or spreadsheet ID needs to become compiled context. Executable truth lives at connectors/sheets.py; this skill is a signpost, never a second implementation.
 ---
 
-# sheets_readonly โ€” signpost to scripts/connectors/sheets.py
+# sheets_readonly โ€” signpost to connectors/sheets.py
 
 The executable is the specification. Run it; do not reimplement it.
 
 ## The three moves
 
 1. Identity and mint (one-time, interactive):
-   `python scripts/connectors/sheets.py`
+   `python connectors/sheets.py`
    Prints the OAuth wiring status (credentials.json path, its project_id,
    token path) and, in a real terminal, mints ~/.config/pipulate/sheets_token.json
    via the browser handshake. After that, every run is headless.
 
 2. LIST with size gauge:
-   `python scripts/connectors/sheets.py "<URL-or-ID>"`
+   `python connectors/sheets.py "<URL-or-ID>"`
    Every tab's rows x cols x ~cells prints BEFORE any fetch; overflow-shaped
    tabs are flagged. A #gid= fragment in a pasted URL selects that tab and
    performs a bounded fetch of it directly.
@@ -37,4 +37,4 @@ The executable is the specification. Run it; do not reimplement it.
   means your own account cannot open that sheet.
 - Errors and auth guidance ride stderr; stdout stays parseable.
 
-See scripts/connectors/README.md for the full connector contract.
+See connectors/README.md for the full connector contract.
diff --git a/apply.py b/apply.py
index 0bcf7951..2c160069 100644
--- a/apply.py
+++ b/apply.py
@@ -76,7 +76,7 @@ import subprocess
 #      output to stay safe must first prove the exit code ALONE still
 #      answers the question; otherwise it has traded content for silence and
 #      kept neither. Two sibling misses the same day: a probe reading
-#      scripts/connectors/wallet.json, a path that has never existed, and a
+#      connectors/wallet.json, a path that has never existed, and a
 #      `jira | grep -c` whose 2>/dev/null made a dead credential and an
 #      empty ticket list print the same 0.
 # THE HELP TEXT IS NOT A CENSUS (convicted 2026-09-17, both halves of one
diff --git a/assets/trails/botify_pageworkers.yaml b/assets/trails/botify_pageworkers.yaml
index 20f1e045..d3b47de0 100644
--- a/assets/trails/botify_pageworkers.yaml
+++ b/assets/trails/botify_pageworkers.yaml
@@ -21,7 +21,7 @@
       "target_slot": "optimization_project",
       "harvest_regex": "^[^/\\s]+/[^/\\s]+$",
       "connector": {
-        "script": "scripts/connectors/botify.py",
+        "script": "connectors/botify.py",
         "argv": ["{harvested}", "-n", "25"],
         "read_only": true
       }
@@ -34,7 +34,7 @@
       "target_slot": "monitoring_project",
       "harvest_regex": "^[^/\\s]+/[^/\\s]+$",
       "connector": {
-        "script": "scripts/connectors/botify.py",
+        "script": "connectors/botify.py",
         "argv": ["{harvested}", "-n", "25"],
         "read_only": true
       }
@@ -47,7 +47,7 @@
       "target_slot": "reporting_project",
       "harvest_regex": "^[^/\\s]+/[^/\\s]+$",
       "connector": {
-        "script": "scripts/connectors/botify.py",
+        "script": "connectors/botify.py",
         "argv": ["{harvested}", "-n", "25"],
         "read_only": true
       }
diff --git a/assets/trails/first_context.yaml b/assets/trails/first_context.yaml
index 91e2b332..2ce78477 100644
--- a/assets/trails/first_context.yaml
+++ b/assets/trails/first_context.yaml
@@ -21,7 +21,7 @@
       "target_slot": "jira_issue_key",
       "harvest_regex": "^[A-Z][A-Z0-9]+-[0-9]+$",
       "connector": {
-        "script": "scripts/connectors/jira.py",
+        "script": "connectors/jira.py",
         "argv": ["{harvested}", "-n", "25"],
         "read_only": true
       }
@@ -34,7 +34,7 @@
       "target_slot": "botify_project",
       "harvest_regex": "^[^/\\s]+/[^/\\s]+$",
       "connector": {
-        "script": "scripts/connectors/botify.py",
+        "script": "connectors/botify.py",
         "argv": ["{harvested}", "-n", "25"],
         "read_only": true
       }
@@ -47,7 +47,7 @@
       "target_slot": "gmail_thread",
       "harvest_regex": "^[^@\\s]+$",
       "connector": {
-        "script": "scripts/connectors/gmail.py",
+        "script": "connectors/gmail.py",
         "argv": ["{harvested}", "-n", "10"],
         "read_only": true
       }
diff --git a/assets/trails/jira_for_you.yaml b/assets/trails/jira_for_you.yaml
index d086faf3..18325a08 100644
--- a/assets/trails/jira_for_you.yaml
+++ b/assets/trails/jira_for_you.yaml
@@ -21,7 +21,7 @@
       "target_slot": "jira_issue_key",
       "harvest_regex": "^[A-Z][A-Z0-9]+-[0-9]+$",
       "connector": {
-        "script": "scripts/connectors/jira.py",
+        "script": "connectors/jira.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
diff --git a/assets/trails/public_walk.json b/assets/trails/public_walk.json
index cfcc2ef0..d26621b2 100644
--- a/assets/trails/public_walk.json
+++ b/assets/trails/public_walk.json
@@ -21,7 +21,7 @@
       "target_slot": "slot_one",
       "harvest_regex": ".+",
       "connector": {
-        "script": "scripts/connectors/noop.py",
+        "script": "connectors/noop.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
@@ -34,7 +34,7 @@
       "target_slot": "slot_two",
       "harvest_regex": ".+",
       "connector": {
-        "script": "scripts/connectors/noop.py",
+        "script": "connectors/noop.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
@@ -47,7 +47,7 @@
       "target_slot": "slot_three",
       "harvest_regex": ".+",
       "connector": {
-        "script": "scripts/connectors/noop.py",
+        "script": "connectors/noop.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
diff --git a/assets/trails/se_ticket.yaml b/assets/trails/se_ticket.yaml
index 32339cff..ab818e9a 100644
--- a/assets/trails/se_ticket.yaml
+++ b/assets/trails/se_ticket.yaml
@@ -21,7 +21,7 @@
       "target_slot": "jira_issue_key",
       "harvest_regex": "^[A-Z][A-Z0-9]+-[0-9]+$",
       "connector": {
-        "script": "scripts/connectors/jira.py",
+        "script": "connectors/jira.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
@@ -34,7 +34,7 @@
       "target_slot": "botify_project",
       "harvest_regex": "^[^/\\s]+/[^/\\s]+$",
       "connector": {
-        "script": "scripts/connectors/botify.py",
+        "script": "connectors/botify.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
@@ -48,7 +48,7 @@
       "target_slot": "botify_analysis",
       "harvest_regex": "^[0-9]{8}(-[0-9]+)?$",
       "connector": {
-        "script": "scripts/connectors/botify.py",
+        "script": "connectors/botify.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
@@ -62,7 +62,7 @@
       "target_slot": "slack_channel",
       "harvest_regex": "^[CG][A-Z0-9]+$",
       "connector": {
-        "script": "scripts/connectors/slack.py",
+        "script": "connectors/slack.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
@@ -76,7 +76,7 @@
       "target_slot": "confluence_space",
       "harvest_regex": "^[A-Z][A-Z0-9]*$",
       "connector": {
-        "script": "scripts/connectors/confluence.py",
+        "script": "connectors/confluence.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
diff --git a/assets/trails/ticket.yaml b/assets/trails/ticket.yaml
index 68e65af1..30122276 100644
--- a/assets/trails/ticket.yaml
+++ b/assets/trails/ticket.yaml
@@ -21,7 +21,7 @@
       "target_slot": "jira_issue_key",
       "harvest_regex": "^[A-Z][A-Z0-9]+-[0-9]+$",
       "connector": {
-        "script": "scripts/connectors/jira.py",
+        "script": "connectors/jira.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
@@ -35,7 +35,7 @@
       "target_slot": "botify_project",
       "harvest_regex": "^[^/\\s]+/[^/\\s]+$",
       "connector": {
-        "script": "scripts/connectors/botify.py",
+        "script": "connectors/botify.py",
         "argv": ["{harvested}"],
         "read_only": true
       }
diff --git a/connectors/botify.py b/connectors/botify.py
index ebe5c8e9..61f2f215 100644
--- a/connectors/botify.py
+++ b/connectors/botify.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# scripts/connectors/botify.py
+# connectors/botify.py
 """
 botify.py โ€” Bring Botify crawl data and BQL query results into context.
 
@@ -7,23 +7,23 @@ A Unix-philosophy gateway to the Botify API for Prompt Fu context.
 
 Golden-path modes, auto-detected from the single positional argument:
 
-  python scripts/connectors/botify.py                    # LIST: identity walk -> all your org/project slugs
-  python scripts/connectors/botify.py org                # LIST: projects under that org slug
-  python scripts/connectors/botify.py org/project        # LIST: analyses (crawl snapshots) for that project
-  python scripts/connectors/botify.py org/project/analysis    # FETCH: verdict (status, pages, rate, cadence ETA) + crawl statistics, running or done
-  python scripts/connectors/botify.py 'https://app.botify.com/org/project/...'   # any app URL reduces to its slug path first
-  python scripts/connectors/botify.py org/project/saved_explorers --grep facet   # DRILL: any project sub-resource, rows narrowed
-  python scripts/connectors/botify.py org/project/saved_explorers/<uuid>   # FETCH: one item in full, containers as JSON
-  python scripts/connectors/botify.py org/project/analysis/crawl_statistics   # DRILL: any analysis sub-resource; a ?k=v rides along
-  python scripts/connectors/botify.py org/project/collections/crawl.<slug> --grep link   # FIND: every leaf path in one object matching
-  python scripts/connectors/botify.py org/project/analysis --grep link   # the verdict, then every leaf in the detail matching
-  python scripts/connectors/botify.py '<BQL or JSON>'    # FETCH: run a query (needs org/project coordinates)
+  python connectors/botify.py                    # LIST: identity walk -> all your org/project slugs
+  python connectors/botify.py org                # LIST: projects under that org slug
+  python connectors/botify.py org/project        # LIST: analyses (crawl snapshots) for that project
+  python connectors/botify.py org/project/analysis    # FETCH: verdict (status, pages, rate, cadence ETA) + crawl statistics, running or done
+  python connectors/botify.py 'https://app.botify.com/org/project/...'   # any app URL reduces to its slug path first
+  python connectors/botify.py org/project/saved_explorers --grep facet   # DRILL: any project sub-resource, rows narrowed
+  python connectors/botify.py org/project/saved_explorers/<uuid>   # FETCH: one item in full, containers as JSON
+  python connectors/botify.py org/project/analysis/crawl_statistics   # DRILL: any analysis sub-resource; a ?k=v rides along
+  python connectors/botify.py org/project/collections/crawl.<slug> --grep link   # FIND: every leaf path in one object matching
+  python connectors/botify.py org/project/analysis --grep link   # the verdict, then every leaf in the detail matching
+  python connectors/botify.py '<BQL or JSON>'    # FETCH: run a query (needs org/project coordinates)
 
 Designed to be dropped into adhoc.txt as a `!` chisel-strike, e.g.:
 
-  ! python scripts/connectors/botify.py
-  ! python scripts/connectors/botify.py my-org/my-project
-  ! python scripts/connectors/botify.py 'SELECT url FROM crawl' --org my-org --project my-project
+  ! python connectors/botify.py
+  ! python connectors/botify.py my-org/my-project
+  ! python connectors/botify.py 'SELECT url FROM crawl' --org my-org --project my-project
 
 Disambiguation rule: an argument that starts with '{' or contains whitespace is
 a query (FETCH mode); an app.botify.com URL is first reduced to its slug path
@@ -187,7 +187,7 @@ def list_identity(client, max_items):
     for p in projects:
         org, slug, name = project_coordinates(p)
         print(f"{org}/{slug}  {name}")
-    print("\n# Next: python scripts/connectors/botify.py <org>/<project>   (list analyses)")
+    print("\n# Next: python connectors/botify.py <org>/<project>   (list analyses)")
 
 
 def list_org_projects(client, org, max_items):
@@ -200,7 +200,7 @@ def list_org_projects(client, org, max_items):
     for p in projects:
         _, slug, name = project_coordinates(p)
         print(f"{org}/{slug}  {name}")
-    print("\n# Next: python scripts/connectors/botify.py " + org + "/<project>   (list analyses)")
+    print("\n# Next: python connectors/botify.py " + org + "/<project>   (list analyses)")
 
 
 def list_analyses(client, org, project, max_items):
@@ -216,10 +216,10 @@ def list_analyses(client, org, project, max_items):
         finished = a.get("date_finished") or a.get("date_created") or ""
         print(f"{slug}  {status}  {finished}")
     print(
-        "\n# Next: python scripts/connectors/botify.py 'SELECT url FROM crawl' "
+        "\n# Next: python connectors/botify.py 'SELECT url FROM crawl' "
         f"--org {org} --project {project}"
     )
-    print(f"#       python scripts/connectors/botify.py {org}/{project}/<analysis>   (one crawl's status + statistics;")
+    print(f"#       python connectors/botify.py {org}/{project}/<analysis>   (one crawl's status + statistics;")
     print("#       a crawl still RUNNING can be absent from the list above -- fetch it by its slug)")
 
 
@@ -422,7 +422,7 @@ def fetch_analysis(client, org, project, slug, max_items, grep=None):
         print(f"\n## grep {grep!r}: {len(hits)} of {total} leaf(ves) in the analysis detail   (path: value)")
         for path, value in hits:
             print(f"{path}: {value}")
-    print(f"\n# Next: python scripts/connectors/botify.py {org}/{project}   (every finished analysis)")
+    print(f"\n# Next: python connectors/botify.py {org}/{project}   (every finished analysis)")
 
 
 def row_label(item):
@@ -557,7 +557,7 @@ def walk_path(client, org, project, rest, max_items, grep=None):
             print(json.dumps(r, default=str)[:200])
     if isinstance(data, dict) and data.get("next"):
         print("\n# (more pages exist on the server; this printed the first)")
-    print(f"\n# Next: python scripts/connectors/botify.py {org}/{project}/{'/'.join(segs)}/<ident>   (one item in full)")
+    print(f"\n# Next: python connectors/botify.py {org}/{project}/{'/'.join(segs)}/<ident>   (one item in full)")
 
 
 def run_query(client, raw_query, org, project, max_items):
diff --git a/connectors/gmail.py b/connectors/gmail.py
index 1ad8e800..e99d3895 100644
--- a/connectors/gmail.py
+++ b/connectors/gmail.py
@@ -318,7 +318,7 @@ def search_threads(service, subject, max_results, full=True):
         if snippet:
             print(f"    snippet: {snippet}")
         print()
-    print("# Next: python scripts/connectors/gmail.py <thread_id>   (full transcript)")
+    print("# Next: python connectors/gmail.py <thread_id>   (full transcript)")
 
 
 def fetch_thread(service, thread_id):
@@ -390,7 +390,7 @@ def check():
         if not (creds.expired and creds.refresh_token):
             sys.stderr.write(
                 "gmail RED gate1: token invalid and not refreshable -- run "
-                "`python scripts/connectors/wallet.py login gmail`\n")
+                "`python connectors/wallet.py login gmail`\n")
             return 1
         try:
             creds.refresh(Request())
@@ -460,7 +460,7 @@ def main():
                     "which the Gmail\nAPI never returns and cannot convert to a "
                     "thread id. Search by subject\ninstead and FETCH the hex thread "
                     "id it prints:\n"
-                    '    python scripts/connectors/gmail.py "SM Store Locator upgrade"\n'
+                    '    python connectors/gmail.py "SM Store Locator upgrade"\n'
                 )
                 sys.exit(1)
         elif '@' in query:
diff --git a/connectors/gsc.py b/connectors/gsc.py
index a3453847..d13b5fc5 100644
--- a/connectors/gsc.py
+++ b/connectors/gsc.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# scripts/connectors/gsc.py
+# connectors/gsc.py
 """
 gsc.py โ€” Bring Search Console properties or top queries into context.
 
@@ -7,15 +7,15 @@ A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
 
 Golden-path modes, auto-detected from the single positional argument:
 
-  python scripts/connectors/gsc.py                          # LIST: properties visible to the service account
-  python scripts/connectors/gsc.py sc-domain:example.com    # LIST: top queries, last 28 days
-  python scripts/connectors/gsc.py '{"startDate": ...}'     # FETCH: raw searchanalytics JSON body
+  python connectors/gsc.py                          # LIST: properties visible to the service account
+  python connectors/gsc.py sc-domain:example.com    # LIST: top queries, last 28 days
+  python connectors/gsc.py '{"startDate": ...}'     # FETCH: raw searchanalytics JSON body
 
 Designed to be dropped into adhoc.txt as a `!` chisel-strike, e.g.:
 
-  ! python scripts/connectors/gsc.py
-  ! python scripts/connectors/gsc.py sc-domain:mikelev.in
-  ! python scripts/connectors/gsc.py '{"startDate":"2026-06-01","endDate":"2026-06-28","dimensions":["page"]}' --site sc-domain:mikelev.in
+  ! python connectors/gsc.py
+  ! python connectors/gsc.py sc-domain:mikelev.in
+  ! python connectors/gsc.py '{"startDate":"2026-06-01","endDate":"2026-06-28","dimensions":["page"]}' --site sc-domain:mikelev.in
 
 Disambiguation rule: an argument that starts with '{' or contains whitespace is
 a raw searchanalytics query body (FETCH mode; needs --site or PIPULATE_GSC_SITE);
@@ -32,7 +32,7 @@ Auth (oauth_token_file โ€” the same user-OAuth walk as gmail.py and sheets.py):
   A valid token refreshes headlessly, and the token file is REWRITTEN on
   every refresh so the wallet's offline mtime heuristic tracks "last
   refreshed". A missing or dead token browser-mints ONLY on a real TTY โ€”
-  `python scripts/connectors/wallet.py login gsc` is the one-time mint,
+  `python connectors/wallet.py login gsc` is the one-time mint,
   exactly as for gmail and sheets. No service account anywhere.
 
 Output is capped by -n/--max (default 25) per THE PROBE ECONOMY RULE: stdout is
@@ -140,13 +140,13 @@ def get_service():
                 f"GSC OAuth needs the Desktop-app client JSON at: {creds_path}\n"
                 "It is the same credentials.json the gmail/sheets connectors mint\n"
                 "from. Download it once from the Google Cloud Console, then run:\n"
-                "    python scripts/connectors/wallet.py login gsc"
+                "    python connectors/wallet.py login gsc"
             )
         if not sys.stdin.isatty():
             die(
                 f"GSC token not usable ({reason}) and no TTY to browser-mint.\n"
                 "In a real terminal, run:\n"
-                "    python scripts/connectors/wallet.py login gsc"
+                "    python connectors/wallet.py login gsc"
             )
         flow = InstalledAppFlow.from_client_secrets_file(str(creds_path), SCOPES)
         creds = flow.run_local_server(port=0)
@@ -169,7 +169,7 @@ def check():
     if creds is None:
         sys.stderr.write(
             f"gsc RED gate1: {reason} -- run "
-            "`python scripts/connectors/wallet.py login gsc`\n")
+            "`python connectors/wallet.py login gsc`\n")
         return 1
     socket.setdefaulttimeout(15)
     try:
@@ -202,7 +202,7 @@ def list_properties(service, max_items):
         return
     for e in sorted(entries, key=lambda x: x.get('siteUrl', ''))[:max_items]:
         print(f"{e.get('siteUrl', '?')}  [{e.get('permissionLevel', '?')}]")
-    print("\n# Next: python scripts/connectors/gsc.py sc-domain:example.com   "
+    print("\n# Next: python connectors/gsc.py sc-domain:example.com   "
           "(top queries, last 28 days)")
 
 
@@ -228,7 +228,7 @@ def list_top_queries(service, site, max_items):
         q = (r.get('keys') or ['?'])[0]
         print(f"{int(r.get('clicks', 0)):>7}  {int(r.get('impressions', 0)):>8}  "
               f"{100 * r.get('ctr', 0):>6.2f}  {r.get('position', 0):>6.1f}  {q}")
-    print("\n# Next: python scripts/connectors/gsc.py "
+    print("\n# Next: python connectors/gsc.py "
           "'{\"startDate\":\"" + start.isoformat() + "\",\"endDate\":\"" + end.isoformat() +
           "\",\"dimensions\":[\"page\"]}' --site " + site)
 
diff --git a/connectors/jira.py b/connectors/jira.py
index a3dbc881..3d2b6a03 100644
--- a/connectors/jira.py
+++ b/connectors/jira.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# scripts/connectors/jira.py
+# connectors/jira.py
 """
 jira.py โ€” List your open Jira tickets, or fetch one by key.
 
@@ -7,17 +7,17 @@ A Unix-philosophy gateway to the Jira Cloud API for Prompt Fu context.
 
 Golden-path modes, auto-detected from the single positional argument:
 
-  python scripts/connectors/jira.py                 # MINE: open issues assigned to you (the For You tab)
-  python scripts/connectors/jira.py projects        # LIST: projects you can see
-  python scripts/connectors/jira.py ENG             # LIST: recently-updated issues in project ENG
-  python scripts/connectors/jira.py ENG-123         # FETCH: full text of one issue (custom fields + description + comments)
-  python scripts/connectors/jira.py 'assignee = currentUser() ORDER BY updated DESC'  # SEARCH: raw JQL
+  python connectors/jira.py                 # MINE: open issues assigned to you (the For You tab)
+  python connectors/jira.py projects        # LIST: projects you can see
+  python connectors/jira.py ENG             # LIST: recently-updated issues in project ENG
+  python connectors/jira.py ENG-123         # FETCH: full text of one issue (custom fields + description + comments)
+  python connectors/jira.py 'assignee = currentUser() ORDER BY updated DESC'  # SEARCH: raw JQL
 
 Designed to be dropped into adhoc.txt as a `!` chisel-strike, e.g.:
 
-  ! python scripts/connectors/jira.py
-  ! python scripts/connectors/jira.py ENG
-  ! python scripts/connectors/jira.py ENG-123
+  ! python connectors/jira.py
+  ! python connectors/jira.py ENG
+  ! python connectors/jira.py ENG-123
 
 Disambiguation rule (checked in this order):
   - no argument                          -> MINE: open issues assigned to you
@@ -419,7 +419,7 @@ def list_projects(client, base, max_items):
         return
     for p in values[:max_items]:
         print(f"{p.get('key', '?')}  {p.get('name', '')}")
-    print("\n# Next: python scripts/connectors/jira.py <PROJECTKEY>   (recent issues)")
+    print("\n# Next: python connectors/jira.py <PROJECTKEY>   (recent issues)")
 
 
 def _search(client, base, jql, max_items):
@@ -442,7 +442,7 @@ def list_project_issues(client, base, project_key, max_items):
         f = it.get("fields", {})
         print(f"{it.get('key', '?')}  [{_name(f.get('status'))}]  "
               f"[{_name(f.get('issuetype'))}]  {f.get('summary', '')}")
-    print("\n# Next: python scripts/connectors/jira.py <PROJ-123>   (full issue text)")
+    print("\n# Next: python connectors/jira.py <PROJ-123>   (full issue text)")
 
 
 def search_issues(client, base, jql, max_items):
@@ -455,7 +455,7 @@ def search_issues(client, base, jql, max_items):
     for it in issues[:max_items]:
         f = it.get("fields", {})
         print(f"{it.get('key', '?')}  [{_name(f.get('status'))}]  {f.get('summary', '')}")
-    print("\n# Next: python scripts/connectors/jira.py <PROJ-123>   (full issue text)")
+    print("\n# Next: python connectors/jira.py <PROJ-123>   (full issue text)")
 
 
 def list_mine(client, base, max_items):
@@ -478,8 +478,8 @@ def list_mine(client, base, max_items):
               f"[{_name(f.get('priority'))}]  {f.get('summary', '')}")
     if len(issues) >= max_items:
         print(f"\n# (capped at {max_items}; raise -n/--max to see the rest)")
-    print("\n# Next: python scripts/connectors/jira.py <PROJ-123>   (full issue text)")
-    print("#       python scripts/connectors/jira.py projects      (every project you can see)")
+    print("\n# Next: python connectors/jira.py <PROJ-123>   (full issue text)")
+    print("#       python connectors/jira.py projects      (every project you can see)")
 
 
 def fetch_issue(client, base, issue_key):
diff --git a/connectors/mcp.py b/connectors/mcp.py
index f669c8ee..7ba804a2 100644
--- a/connectors/mcp.py
+++ b/connectors/mcp.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# scripts/connectors/mcp.py
+# connectors/mcp.py
 """
 mcp.py โ€” Replay client for remote MCP servers (Streamable HTTP transport).
 
@@ -11,15 +11,15 @@ named gate; nothing here silently falls back.
 
 Golden-path modes, auto-detected from positionals:
 
-  python scripts/connectors/mcp.py                                # IDENTITY: token state + usage; opens no socket
-  python scripts/connectors/mcp.py <server>                       # LIST: initialize -> tools/list (+ server instructions)
-  python scripts/connectors/mcp.py <server> --schema              # LIST: each tool's full JSON (description + inputSchema)
-  python scripts/connectors/mcp.py <server> <tool> '<args-json>'  # CALL: initialize -> tools/call
-  python scripts/connectors/mcp.py <server> --check               # CHECK: envelope health; exit code is the answer
+  python connectors/mcp.py                                # IDENTITY: token state + usage; opens no socket
+  python connectors/mcp.py <server>                       # LIST: initialize -> tools/list (+ server instructions)
+  python connectors/mcp.py <server> --schema              # LIST: each tool's full JSON (description + inputSchema)
+  python connectors/mcp.py <server> <tool> '<args-json>'  # CALL: initialize -> tools/call
+  python connectors/mcp.py <server> --check               # CHECK: envelope health; exit code is the answer
 
 Designed to be dropped into adhoc.txt as a `!` chisel-strike:
 
-  ! python scripts/connectors/mcp.py https://mcp.botify.com --check; echo "exit=$?"
+  ! python connectors/mcp.py https://mcp.botify.com --check; echo "exit=$?"
 
 THE FOUR-TUPLE RECEIPT: every call prints (server, verb, tool, args) with args
 echoed BYTE-FOR-BYTE from argv โ€” the raw string as submitted, never a
@@ -156,7 +156,7 @@ DCLASS_NOTE = {
 # quote() escapes every character a path could carry, and adding an Nth server
 # costs zero configuration lines.
 #
-# token_path_for IS DUPLICATED VERBATIM in scripts/connectors/mcp_warm.py, on
+# token_path_for IS DUPLICATED VERBATIM in connectors/mcp_warm.py, on
 # purpose: the connector contract makes each file self-contained (no shared
 # imports), and walk_cartridge.py already duplicates foo_cartridge's primitives
 # for the same reason. The two definitions must stay byte-identical, so the
@@ -255,7 +255,7 @@ def _expiry_note(data):
     has_refresh = "yes" if data.get("refresh_token") else "no"
     return (f"EXPIRED {int(-remaining)}s ago (life was {int(life)}s); "
             f"refresh_token present: {has_refresh}; re-mint with "
-            "python scripts/connectors/mcp_warm.py")
+            "python connectors/mcp_warm.py")
 
 
 def resolve_token(token_env=None, server=None):
@@ -373,7 +373,7 @@ def identity():
     print("#   mcp <server>                   initialize -> tools/list")
     print("#   mcp <server> <tool> '<json>'   initialize -> tools/call")
     print("#")
-    print("# Mint or refresh a bearer:  python scripts/connectors/mcp_warm.py")
+    print("# Mint or refresh a bearer:  python connectors/mcp_warm.py")
 
 
 def make_client(token, scheme="Bearer"):
diff --git a/connectors/mcp_warm.py b/connectors/mcp_warm.py
index 1739f8c6..00629398 100644
--- a/connectors/mcp_warm.py
+++ b/connectors/mcp_warm.py
@@ -1,9 +1,9 @@
 #!/usr/bin/env python3
-# scripts/connectors/mcp_warm.py
+# connectors/mcp_warm.py
 """
 mcp_warm.py โ€” Mint the OAuth bearer token a remote MCP server asks for.
 
-OAuth 2.1 with PKCE (S256), parked where scripts/connectors/mcp.py already
+OAuth 2.1 with PKCE (S256), parked where connectors/mcp.py already
 looks.
 
 THE PLUG FOR THE ALREADY-WIRED SOCKET: resolve_token() in mcp.py reads
@@ -16,8 +16,8 @@ No new dependencies: httpx (declared) plus stdlib.
 
 Golden path:
 
-  python scripts/connectors/mcp_warm.py                      # https://mcp.botify.com/
-  python scripts/connectors/mcp_warm.py https://mcp.example.com/
+  python connectors/mcp_warm.py                      # https://mcp.botify.com/
+  python connectors/mcp_warm.py https://mcp.example.com/
 
 Interactive-only BY DESIGN: it opens a browser and blocks on the redirect,
 so a `!` chisel-strike must never reach it. Non-TTY runs die at gate0.
@@ -63,7 +63,7 @@ AUTH_TIMEOUT = 300  # seconds to wait for the browser redirect
 def token_path_for(resource):
     """Credential path for one MCP server. A root path collapses to the host.
 
-    DUPLICATED VERBATIM from scripts/connectors/mcp.py, on purpose: each
+    DUPLICATED VERBATIM from connectors/mcp.py, on purpose: each
     connector is self-contained (no shared imports), and a shared helper would
     make mcp.py depend on this file. The two definitions must stay
     byte-identical; the straddle probe compares their output.
@@ -270,7 +270,7 @@ def refresh(out_path, resource_hint=DEFAULT_RESOURCE):
     print(f"# gate6 GREEN: refreshed in place -> {out} (0600)")
     print(f"#   scope: {record.get('scope') or '(none reported)'} | "
           f"expires_in: {record.get('expires_in')}")
-    print("# Next: python scripts/connectors/mcp.py "
+    print("# Next: python connectors/mcp.py "
           f"{resource.rstrip('/')} --check")
     return 0
 
@@ -399,7 +399,7 @@ def main():
     print(f"# gate5 GREEN: token written to {out} (0600)")
     print(f"#   scope: {record['scope'] or '(none reported)'} | "
           f"expires_in: {record['expires_in']}")
-    print("# Next: python scripts/connectors/mcp.py "
+    print("# Next: python connectors/mcp.py "
           f"{resource.rstrip('/')} --check")
 
 
diff --git a/connectors/noop.py b/connectors/noop.py
index f49d859a..048c2e33 100644
--- a/connectors/noop.py
+++ b/connectors/noop.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# scripts/connectors/noop.py
+# connectors/noop.py
 """
 noop.py -- Accept one value, print it, exit 0. The honest placeholder.
 
diff --git a/connectors/sheets.py b/connectors/sheets.py
index 7bbe0a6a..bfdcf04a 100644
--- a/connectors/sheets.py
+++ b/connectors/sheets.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# scripts/connectors/sheets.py
+# connectors/sheets.py
 """
 sheets.py โ€” Bring a Google Sheet's tabs and cell data into context.
 
@@ -7,17 +7,17 @@ A Unix-philosophy gateway to Google Sheets for Prompt Fu context.
 
 Golden-path modes, auto-detected from the single positional argument:
 
-  python scripts/connectors/sheets.py                        # IDENTITY: OAuth wiring status; mints the token interactively
-  python scripts/connectors/sheets.py <URL-or-ID>            # STACK: every tab's ACTUAL data rectangle, timestamped and stacked vertically with payload-grammar sentinels + clickable per-tab #gid= URLs (over --budget: true-extent gauge instead)
-  python scripts/connectors/sheets.py <URL-or-ID> --list     # LIST: metadata-only gauge (grid ALLOCATION, zero cell data fetched)
-  python scripts/connectors/sheets.py <URL-or-ID> --sheet Metrics             # FETCH: first --max rows of one named tab
-  python scripts/connectors/sheets.py <URL-or-ID> --range "'Metrics'!A1:F50"  # FETCH: explicit A1 range
+  python connectors/sheets.py                        # IDENTITY: OAuth wiring status; mints the token interactively
+  python connectors/sheets.py <URL-or-ID>            # STACK: every tab's ACTUAL data rectangle, timestamped and stacked vertically with payload-grammar sentinels + clickable per-tab #gid= URLs (over --budget: true-extent gauge instead)
+  python connectors/sheets.py <URL-or-ID> --list     # LIST: metadata-only gauge (grid ALLOCATION, zero cell data fetched)
+  python connectors/sheets.py <URL-or-ID> --sheet Metrics             # FETCH: first --max rows of one named tab
+  python connectors/sheets.py <URL-or-ID> --range "'Metrics'!A1:F50"  # FETCH: explicit A1 range
 
 Designed to be dropped into adhoc.txt as a `!` chisel-strike, e.g.:
 
-  ! python scripts/connectors/sheets.py "https://docs.google.com/spreadsheets/d/<ID>/edit#gid=0"
-  ! python scripts/connectors/sheets.py <ID> --sheet Metrics --max 50
-  ! python scripts/connectors/sheets.py <ID> --range "'Metrics'!A1:F50" --format json
+  ! python connectors/sheets.py "https://docs.google.com/spreadsheets/d/<ID>/edit#gid=0"
+  ! python connectors/sheets.py <ID> --sheet Metrics --max 50
+  ! python connectors/sheets.py <ID> --range "'Metrics'!A1:F50" --format json
 
 Disambiguation rule: no argument prints identity/usage; anything else is a
 spreadsheet coordinate โ€” a full docs.google.com URL (the /d/<ID>/ segment is
@@ -149,7 +149,7 @@ def get_service():
         die(
             "Sheets auth needs a one-time interactive login.\n"
             "Run this directly in your terminal first to mint the token:\n"
-            "    python scripts/connectors/sheets.py\n"
+            "    python connectors/sheets.py\n"
             "After that, `!` invocations inside the compile lane run silently."
         )
 
@@ -194,7 +194,7 @@ def identity():
         print("Token minted. Headless `!` runs will work from here on.")
     elif not token_ok:
         print("\nRun this same command once in a real terminal to mint the token.")
-    print("\n# Next: python scripts/connectors/sheets.py "
+    print("\n# Next: python connectors/sheets.py "
           '"https://docs.google.com/spreadsheets/d/<ID>/edit"   (LIST tabs + sizes)')
 
 
@@ -227,7 +227,7 @@ def list_tabs(service, sid, gid, max_items):
     if len(tabs) > max_items:
         print(f"... +{len(tabs) - max_items} more tab(s) (raise -n/--max)")
     target = first_tab or 'Sheet1'
-    print(f"\n# Next: python scripts/connectors/sheets.py {sid} "
+    print(f"\n# Next: python connectors/sheets.py {sid} "
           f"--sheet \"{target}\"   (first rows, capped by --max)")
 
 
@@ -272,9 +272,9 @@ def stack_tabs(service, sid, fmt, budget):
         for p, _, r, c in extents:
             print(f"{r:>7}  {c:>5}  {r * c:>9,}  {p.get('title', '?')} | "
                   f"{base_url}#gid={p.get('sheetId', 0)}")
-        print(f"\n# Next: python scripts/connectors/sheets.py {sid} "
+        print(f"\n# Next: python connectors/sheets.py {sid} "
               "--sheet \"<Tab>\"   (one bounded tab)")
-        print(f"# Or raise the ceiling: python scripts/connectors/sheets.py "
+        print(f"# Or raise the ceiling: python connectors/sheets.py "
               f"{sid} --budget {total_cells}")
         return
 
@@ -290,7 +290,7 @@ def stack_tabs(service, sid, fmt, budget):
         else:
             print("(empty tab)")
         print(f'--- END: TAB "{name}" ---\n')
-    print(f"# Next: python scripts/connectors/sheets.py {sid} "
+    print(f"# Next: python connectors/sheets.py {sid} "
           "--range \"'<Tab>'!A1:Z50\" --format json   (one precise slab)")
 
 
@@ -346,7 +346,7 @@ def fetch_values(service, sid, sheet, rng, fmt, max_rows):
         return
     _emit(rows, fmt)
     tab_hint = sheet if sheet else '<Tab>'
-    print(f"\n# Next: python scripts/connectors/sheets.py {sid} "
+    print(f"\n# Next: python connectors/sheets.py {sid} "
           f"--range \"'{tab_hint}'!A1:Z{max_rows}\" --format json")
 
 
@@ -403,7 +403,7 @@ def check():
         if not (creds.expired and creds.refresh_token):
             sys.stderr.write(
                 "sheets RED gate1: token invalid and not refreshable -- run "
-                "`python scripts/connectors/wallet.py login sheets`\n")
+                "`python connectors/wallet.py login sheets`\n")
             return 1
         try:
             creds.refresh(Request())
@@ -431,7 +431,7 @@ def check():
     if resp.status_code == 401:
         sys.stderr.write(
             "sheets RED gate2: token rejected (HTTP 401) -- run "
-            "`python scripts/connectors/wallet.py login sheets`\n")
+            "`python connectors/wallet.py login sheets`\n")
         return 1
     if resp.status_code == 403:
         if status == 'SERVICE_DISABLED':
diff --git a/connectors/slack.py b/connectors/slack.py
index 95baeafe..1dad78f7 100644
--- a/connectors/slack.py
+++ b/connectors/slack.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# scripts/connectors/slack.py
+# connectors/slack.py
 """
 slack.py โ€” Bring a Slack channel or message thread into context.
 
@@ -7,18 +7,18 @@ A Unix-philosophy gateway to the Slack Web API for Prompt Fu context.
 
 Golden-path modes, auto-detected from the single positional argument:
 
-  python scripts/connectors/slack.py                 # LIST: channels you can see (+ identity)
-  python scripts/connectors/slack.py C0123ABCD        # LIST: recent messages in that channel
-  python scripts/connectors/slack.py general          # LIST: same, resolving a bare #name to its id
-  python scripts/connectors/slack.py https://you.slack.com/archives/C0123ABCD/p1699999999123456
+  python connectors/slack.py                 # LIST: channels you can see (+ identity)
+  python connectors/slack.py C0123ABCD        # LIST: recent messages in that channel
+  python connectors/slack.py general          # LIST: same, resolving a bare #name to its id
+  python connectors/slack.py https://you.slack.com/archives/C0123ABCD/p1699999999123456
                                                       # FETCH: that thread's parent + all replies
-  python scripts/connectors/slack.py 'deploy failed checkout'   # SEARCH: search.messages (user token)
-  python scripts/connectors/slack.py -w pipulate     # ANY mode, on the workspace whose pair is SLACK_USER_TOKEN_PIPULATE
+  python connectors/slack.py 'deploy failed checkout'   # SEARCH: search.messages (user token)
+  python connectors/slack.py -w pipulate     # ANY mode, on the workspace whose pair is SLACK_USER_TOKEN_PIPULATE
 
 Designed to be dropped into adhoc.txt as a `!` chisel-strike, e.g.:
 
-  ! python scripts/connectors/slack.py
-  ! python scripts/connectors/slack.py C0123ABCD
+  ! python connectors/slack.py
+  ! python connectors/slack.py C0123ABCD
 
 Disambiguation rule (checked in this order):
   - no argument                              -> identity (auth.test) + LIST channels
@@ -366,7 +366,7 @@ def identity_and_list(client, max_items):
         priv = "๐Ÿ”’" if ch.get("is_private") else "#"
         print(f"{ch.get('id', '?')}  {priv}{ch.get('name', '')}  "
               f"[{ch.get('num_members', '?')}]  {topic}")
-    print("\n# Next: python scripts/connectors/slack.py <CHANNEL_ID>   (recent messages)")
+    print("\n# Next: python connectors/slack.py <CHANNEL_ID>   (recent messages)")
 
 
 def list_channel_history(client, channel_arg, max_items):
diff --git a/connectors/wallet.py b/connectors/wallet.py
index 7cf693fe..95887940 100644
--- a/connectors/wallet.py
+++ b/connectors/wallet.py
@@ -1,21 +1,21 @@
 #!/usr/bin/env python3
-# scripts/connectors/wallet.py
+# connectors/wallet.py
 """
 wallet.py โ€” Connect your accounts, or any site by URL; see what's live.
 
 Golden-path modes, auto-detected from the leading positional argument:
 
-  python scripts/connectors/wallet.py                 # SCOREBOARD: stat EVERY slot, whatever its auth kind (OFFLINE)
-  python scripts/connectors/wallet.py check [<slot>]  # CHECK: the red/green game โ€” one bounded probe per enrolled slot
-  python scripts/connectors/wallet.py check <URL>     # CHECK: the cookie verdict for ANY site, offline, no slot needed
-  python scripts/connectors/wallet.py warm [<slot>]   # WARM: fix whatever is cold, dispatched per auth kind
-  python scripts/connectors/wallet.py warm <URL>      # WARM: log into ANY site, no slot needed; profile = apex label
-  python scripts/connectors/wallet.py login <slot>    # LOGIN: mint an oauth slot, or NAME how any other kind is warmed
+  python connectors/wallet.py                 # SCOREBOARD: stat EVERY slot, whatever its auth kind (OFFLINE)
+  python connectors/wallet.py check [<slot>]  # CHECK: the red/green game โ€” one bounded probe per enrolled slot
+  python connectors/wallet.py check <URL>     # CHECK: the cookie verdict for ANY site, offline, no slot needed
+  python connectors/wallet.py warm [<slot>]   # WARM: fix whatever is cold, dispatched per auth kind
+  python connectors/wallet.py warm <URL>      # WARM: log into ANY site, no slot needed; profile = apex label
+  python connectors/wallet.py login <slot>    # LOGIN: mint an oauth slot, or NAME how any other kind is warmed
 
 Designed to be dropped into adhoc.txt as a `!` chisel-strike, e.g.:
 
-  ! python scripts/connectors/wallet.py
-  ! python scripts/connectors/wallet.py -n 5
+  ! python connectors/wallet.py
+  ! python connectors/wallet.py -n 5
 
 This is the GENERALIZATION of each connector's no-argument identity() walk
 lifted from ONE connector to the WHOLE wallet. It reads
@@ -105,7 +105,7 @@ DOTENV_PATH = Path(os.environ.get('PIPULATE_DOTENV') or
 # Repo root anchors browser_session profiles (data/uc_profiles/<name>), the
 # SAME directory weblogin.py writes. weblogin honors PIPULATE_ROOT then falls
 # back to its own parent.parent; wallet.py lives one level deeper
-# (scripts/connectors/), so parents[2] is the repo root. Keep in sync.
+# (connectors/), so parents[2] is the repo root. Keep in sync.
 REPO_ROOT = Path(os.environ.get('PIPULATE_ROOT') or Path(__file__).resolve().parents[2])
 
 # Auth kinds โ€” these strings MUST match connectors.json exactly.
@@ -132,8 +132,8 @@ _KIND_LABEL = {
 _MARK = {'filled': '[x]', 'stale': '[~]', 'partial': '[/]', 'empty': '[ ]',
          'no-path': '[!]', 'unknown': '[?]'}
 
-# THE THIRD VERBATIM COPY. token_path_for lives in scripts/connectors/mcp.py
-# and scripts/connectors/mcp_warm.py; this leg turns the twins into triplets.
+# THE THIRD VERBATIM COPY. token_path_for lives in connectors/mcp.py
+# and connectors/mcp_warm.py; this leg turns the twins into triplets.
 # The WET connector contract forbids wallet.py importing mcp.py, so the
 # derivation is duplicated ON PURPOSE and the copies are COMPARED BY PROBE,
 # never trusted -- the existing twin-agreement probe simply gains a third leg.
@@ -193,19 +193,19 @@ def load_wallet():
         print("#")
         print("# It has one slot -- botify -- with no token yet. To fill it:")
         print("#")
-        print("#   python scripts/connectors/wallet.py warm botify")
+        print("#   python connectors/wallet.py warm botify")
         print("#")
         print("# That prompts for your Botify API token (get one at")
         print("# https://app.botify.com/account), saves it to ~/.config/pipulate/.env")
         print("# (0600, never in git), and confirms. Press Enter with no token to")
         print("# skip -- the slot waits, empty, until you come back to warm it.")
         print("#")
-        print("# Then `python scripts/connectors/wallet.py check` plays the live")
+        print("# Then `python connectors/wallet.py check` plays the live")
         print("# red/green board -- green means the service accepted the credential")
         print("# just now, not merely that a token exists.")
         print("#")
         print("# The slot name is yours; `auth` is one of six kinds (bearer_token")
-        print("# here). See scripts/connectors/README.md for the other five.")
+        print("# here). See connectors/README.md for the other five.")
         sys.exit(0)
     try:
         return json.loads(path.read_text(encoding='utf-8'))
@@ -351,18 +351,18 @@ def _next_hint(name, state, kind):
     """The exact command that warms THIS slot's kind โ€” the connector teaching
     its own use, even for kinds this wallet cannot mint itself."""
     if kind == _OAUTH_KIND:
-        return f"python scripts/connectors/wallet.py login {name}   (browser-mint, one-time)"
+        return f"python connectors/wallet.py login {name}   (browser-mint, one-time)"
     if kind == _SERVICE_KIND:
         return (f"place the service-account key JSON at the path above "
                 f"(Google Cloud Console โ†’ IAM โ†’ Service Accounts)")
     if kind == _BROWSER_KIND:
-        return (f"python scripts/connectors/wallet.py warm {name}   "
+        return (f"python connectors/wallet.py warm {name}   "
                 f"(confirms, then opens this slot's own site + profile)")
     if kind == _MCP_KIND:
-        return (f"python scripts/connectors/wallet.py warm {name}   "
+        return (f"python connectors/wallet.py warm {name}   "
                 f"(headless refresh when the derived file can; else browser mint)")
     if kind in _ENV_KINDS:
-        return (f"python scripts/connectors/wallet.py warm {name}   "
+        return (f"python connectors/wallet.py warm {name}   "
                 f"(prompts for each missing var, saves to {DOTENV_PATH})")
     return "unrecognized kind โ€” check connectors.json `auth`"
 
@@ -483,7 +483,7 @@ def login(slot_name, stale_days):
             "Download the Desktop-app OAuth client JSON from the Google Cloud\n"
             "Console and place it there (the same client the other Google\n"
             "connectors use), then re-run:\n"
-            f"    python scripts/connectors/wallet.py login {slot_name}")
+            f"    python connectors/wallet.py login {slot_name}")
 
     connector_file = Path(__file__).resolve().parent / f"{slot_name}.py"
     if not connector_file.exists():
@@ -805,7 +805,7 @@ def _warm_url(url, stale_days, assume_yes=False, dry_run=False):
     if not _interactive():
         print("\n# Not a TTY -- refusing to open a browser, because a `!` chisel-strike")
         print("# must never block the compile that embedded it. In a real terminal:")
-        print(f"#    python scripts/connectors/wallet.py warm '{url}'")
+        print(f"#    python connectors/wallet.py warm '{url}'")
         return
     print("\n" + "-" * 70)
     note = _warm_browser(label, cfg, assume_yes)
@@ -882,7 +882,7 @@ def warm(slot_name, stale_days, assume_yes=False, dry_run=False):
         target = f" {slot_name}" if slot_name else ''
         print("\n# Not a TTY โ€” refusing to prompt, because a `!` chisel-strike must")
         print("# never block the compile that embedded it. In a real terminal:")
-        print(f"#    python scripts/connectors/wallet.py warm{target}")
+        print(f"#    python connectors/wallet.py warm{target}")
         return
 
     results = []
@@ -1057,7 +1057,7 @@ def check_browser_slot(name, cfg):
     db = _cookie_db(profile_dir)
     if db is None:
         return 1, (f"{name} RED gate1: no cookie store under {profile_dir} โ€” "
-                   f"run `python scripts/connectors/wallet.py warm {name}`")
+                   f"run `python connectors/wallet.py warm {name}`")
     apex = _apex(site)
     now = int((time.time() + _CHROME_EPOCH_OFFSET) * 1_000_000)
     try:
@@ -1282,7 +1282,7 @@ def board(wallet, slot_name):
         print(f"# ๐Ÿ† GOLD โ€” every enrolled credential ({green}/{total}) is live.")
         return 0
     if red:
-        print("# Fix a red:  python scripts/connectors/wallet.py warm <slot>")
+        print("# Fix a red:  python connectors/wallet.py warm <slot>")
     if unchecked:
         print("# An unchecked slot blocks GOLD on purpose: give it a --check, "
               'or bench it with "enrolled": false.')
diff --git a/flake.nix b/flake.nix
index 3972d4ee..79d5e26d 100644
--- a/flake.nix
+++ b/flake.nix
@@ -473,7 +473,7 @@
             echo "${name}: missing $python_bin; enter the Pipulate Nix shell first." >&2
             exit 1
           fi
-          exec "$python_bin" "$root/scripts/connectors/${script}.py" "$@"
+          exec "$python_bin" "$root/connectors/${script}.py" "$@"
         '';
         connectorCommands = [
           (connectorCommand "gmail" "gmail")
@@ -1327,7 +1327,7 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # unrelated jobs and nothing about the word said so: bare `mcp`
           # listed CONNECTORS that pull material IN, while `mcp <tool>`
           # dispatched a REGISTRY TOOL. Worse, `mcp` is the NAME OF A FILE --
-          # scripts/connectors/mcp.py, the one thing here that genuinely IS
+          # connectors/mcp.py, the one thing here that genuinely IS
           # MCP -- and that file could not be reached by its own name because
           # the roster had taken it. Three words now, each of whose bare and
           # argument forms are about the same thing:
@@ -1420,7 +1420,7 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
             fi
           }
           # THE CONNECTOR GRAMMAR (idea #7 made literal): tiny Unix commands,
-          # one per API, each a self-contained file in scripts/connectors/.
+          # one per API, each a self-contained file in connectors/.
           # Args pass through: `botify org/project`, `confluence ENG`,
           # `gmail <thread_id>`. Interactive-shell only โ€” adhoc.txt `!` lines
           # ride as DERIVATIONS in commonPackages above, so the short spelling
@@ -1438,7 +1438,7 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # a function: nothing branches here, because mcp.py's own bare mode is
           # the branch -- and a bare `mcp` that argparse-exited 2 would have
           # been a worse first keypress than the roster it replaced.
-          alias mcp='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/mcp.py"'
+          alias mcp='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/connectors/mcp.py"'
           # weblogin <apex-domain>: pop up a visible Chrome on the house
           # persistent profile (data/uc_profiles/default) so persistent
           # scrapes inherit the login. Log in, close the window, done.
@@ -1497,9 +1497,9 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # reachable.
           warm() {
             if [ "$#" -eq 0 ]; then
-              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/wallet.py" check
+              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/connectors/wallet.py" check
             else
-              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/wallet.py" warm "$@"
+              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/connectors/wallet.py" warm "$@"
             fi
           }
           alias vim='nvim'
diff --git a/foo_files.py b/foo_files.py
index 6dc2f7cb..593f5bf3 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1080,9 +1080,9 @@ foo_files.py      #  <-- THIS file. Content compiler router. Makes it very meta.
 # 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/connectors/gmail.py 19ed7896e9577340  # Performance Baseline Report
-# ! python scripts/connectors/gmail.py 19ef63ffb0dc3ff4  # Google Search Console & GMC Setup
-# ! python scripts/connectors/gmail.py 19ef61f326a3b536  # AI Visibility Tracking Transcript
+# ! python connectors/gmail.py 19ed7896e9577340  # Performance Baseline Report
+# ! python connectors/gmail.py 19ef63ffb0dc3ff4  # Google Search Console & GMC Setup
+# ! python connectors/gmail.py 19ef61f326a3b536  # AI Visibility Tracking Transcript
 
 # KEEP EXPANDING THIS FOR BETTER ONGOING CONFLUENCE ARTICLE SANITIZING
 # ~/.config/pipulate/pii_substitutions.txt
@@ -1883,18 +1883,18 @@ prompt_foo.py               # <-- THIS system
 # of 61, and mcp_warm.py's wraps mid-sentence, so the panel prints a fragment;
 # one car, both files in context. README.md has no docstring; its line is authored.
 # scripts/sources_menu.py          # <-- what door 2 opens onto.
-# scripts/connectors/README.md     # <-- the contract, the wallet, and the six auth kinds every new connector copies one of
-# scripts/connectors/wallet.py     # <-- Connect your accounts, or any site by URL; see what's live.
-# scripts/connectors/botify.py     # <-- Bring Botify crawl data and BQL query results into context.
-# scripts/connectors/confluence.py # <-- Bring a Confluence space, page, or search hit into context.
-# scripts/connectors/gmail.py      # <-- Bring an email thread or a sender's threads into context.
-# scripts/connectors/gsc.py        # <-- A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
-# scripts/connectors/jira.py       # <-- List your open Jira tickets, or fetch one by key.
-# scripts/connectors/sheets.py     # <-- Bring a Google Sheet's tabs and cell data into context.
-# scripts/connectors/slack.py      # <-- Bring a Slack channel or message thread into context.
-# scripts/connectors/mcp.py        # <-- Replay client for remote MCP servers (Streamable HTTP transport).
-# scripts/connectors/mcp_warm.py  # <-- One-shot OAuth 2.1 PKCE warmer; writes the token file mcp.py's resolve_token already reads
-# scripts/connectors/noop.py      # <-- The honest non-operative connector: one positional, prints what it received, exits 0; what public_walk.yaml names at every stop, because a plan must name something that RUNS
+# connectors/README.md     # <-- the contract, the wallet, and the six auth kinds every new connector copies one of
+# connectors/wallet.py     # <-- Connect your accounts, or any site by URL; see what's live.
+# connectors/botify.py     # <-- Bring Botify crawl data and BQL query results into context.
+# connectors/confluence.py # <-- Bring a Confluence space, page, or search hit into context.
+# connectors/gmail.py      # <-- Bring an email thread or a sender's threads into context.
+# connectors/gsc.py        # <-- A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
+# connectors/jira.py       # <-- List your open Jira tickets, or fetch one by key.
+# connectors/sheets.py     # <-- Bring a Google Sheet's tabs and cell data into context.
+# connectors/slack.py      # <-- Bring a Slack channel or message thread into context.
+# connectors/mcp.py        # <-- Replay client for remote MCP servers (Streamable HTTP transport).
+# connectors/mcp_warm.py  # <-- One-shot OAuth 2.1 PKCE warmer; writes the token file mcp.py's resolve_token already reads
+# connectors/noop.py      # <-- The honest non-operative connector: one positional, prints what it received, exits 0; what public_walk.yaml names at every stop, because a plan must name something that RUNS
 # scripts/mcp_dummy_server.py     # <-- The fault harness behind mcp.py (20/20 against the unmodified client); it shares mcp.py's spec reading, so its agreement is a tautology, never a vendor witness
 #  _____ _           _           _   _                      
 # |  ___(_)_ __   __| |   __ _  | | | | ___  _ __ ___   ___ 
@@ -2361,7 +2361,7 @@ foo_files.py
 # ยง THE GATE SPEAKS A VERDICT (banked 2026-08-30) -- a gate the operator reads prints GO or STOP with its readings beside the word, never bare numbers the operator must match against prose in another paragraph; the MCP range-gate printed 1025 and 1228 (its GO shape) while the next block's prose held 1 and 18, and the operator correctly refused to guess. A gate rides where it fires and says what it found. Corollary of THE SILENCED CHANNEL: a machine-graded outcome is a token, a human-graded one is a word.
 
 # EARMARK 2026-08-31 mcp.py isError: call_tool checks HTTP status only. Witnessed: render without session_id returned 200 with result.isError=true and exit 0, so a failed tools/call is indistinguishable from success by exit code and any && chain continues past it. list_tools and check both inspect the JSON-RPC error field; call_tool inspects neither that nor isError. One branch, when the ride is a building ride.
-# - TODO (found 2026-08-30 in a rg receipt): scripts/connectors/mcp.py:65 still calls the FDR channel PENDING a written-file receipt; the file was witnessed 2026-07-29 on the RED-401 flush. Flip the word when mcp.py rides a payload. PROTECTION-LAG POLARITY, in source.
+# - TODO (found 2026-08-30 in a rg receipt): connectors/mcp.py:65 still calls the FDR channel PENDING a written-file receipt; the file was witnessed 2026-07-29 on the RED-401 flush. Flip the word when mcp.py rides a payload. PROTECTION-LAG POLARITY, in source.
 # EARMARK mcp.py --schema <tool>: print one tool's inputSchema from tools/list as JSON, exit 1 if unlisted. The menu shows name + 80 chars and no schema. Server one exposes tool_documentation (docs by tool id) -- try it first; server two's equivalent UNWITNESSED.
 # EARMARK server two, first tools/call: Cars E and F (2026-08-30) never fired. Menu at -n 60, pick a list_/get_ tool, call with '{}'; the JSON-RPC error is the schema.
 # EARMARK WET connector for server two, AFTER one real call: a botify.py-shaped file hardcoding --auth-scheme Token / BOTIFY_API_TOKEN and three common calls as one positional. ONE new file, with consent.
@@ -2489,7 +2489,7 @@ foo_files.py
 # ยง THE LABEL THAT PROMISES A SIBLING (banked 2026-08-09, discharged 2026-08-21) -- a message printed by one command about what a different command will do is a capability claim the printer does not control; mechanically check the sibling, and when it is a shell function record the shell generation, because a pre-fix shell can make code already fixed look broken.
 # ยง THE FIRST-ERROR FLOOR (banked 2026-08-09) -- a parser reports the first error it cannot get past, so a refusal's line number is a FLOOR on the defect count and never a ceiling; a SEARCH/REPLACE refusal bounds its own region and is diagnosable, a refused WHOLE-FILE write does not, so delete and re-emit rather than hand-repair the one line the parser happened to name. Third refusal class after no-blocks-found and search-block-not-found.
 # ยง THE SILENCED CHANNEL (banked 2026-08-09) -- a probe that discards a stream paired with a caboose whose verdict reads that stream is a verdict that can never be reached, and an exit code four worlds share is not a reading; a program graded by a MACHINE prints its outcome as a token on stdout, and when it also handles client data the outcome goes to stdout and every identifying string to stderr, so 2>/dev/null is compile-lane-safe by construction. Partitions with THE EXIT-CODE PROTOCOL RULE: decisions speak in exit codes, measurements in tokens.
-# ยง THE PLACEHOLDER THAT CLAIMS TO RUN (banked 2026-08-08, discharged 2026-08-30) -- validation passing is not execution passing: walk.py checks that a connector file EXISTS and that {harvested} appears once, and nothing anywhere checks that the script accepts the argv it will be handed, so a consent surface can print "names as runnable" about a command that exits 2. Cure a false label with a TRUE sentence, never a vaguer one -- scripts/connectors/noop.py exists IN ORDER to be a no-op and public_walk.yaml names it at all three stops. And never grade a refusal on an exit code that two worlds share.
+# ยง THE PLACEHOLDER THAT CLAIMS TO RUN (banked 2026-08-08, discharged 2026-08-30) -- validation passing is not execution passing: walk.py checks that a connector file EXISTS and that {harvested} appears once, and nothing anywhere checks that the script accepts the argv it will be handed, so a consent surface can print "names as runnable" about a command that exits 2. Cure a false label with a TRUE sentence, never a vaguer one -- connectors/noop.py exists IN ORDER to be a no-op and public_walk.yaml names it at all three stops. And never grade a refusal on an exit code that two worlds share.
 # ยง THE COMPILED TRAIL (banked 2026-08-08, OWES discharged 2026-08-09) -- a trail has two legitimate forms and conflating them is the confusion: the SEALED form is machine cargo and stays the JSON subset of YAML 1.2 because there is no stdlib YAML parser, because the sealer hashes those exact bytes and recomputes the consent surface from them, and because duplicate keys must fail closed; the AUTHORING form is a different artifact and may be prose-shaped, one SECTION per stop, parsed by a ten-line scalar subset. The seal was already the compiler; what was missing was a human-shaped input, and walk_compile.py plus bookmark_import.py landed it.
 # - EARMARK: THE UNREACHABLE GUARD (banked 2026-08-07, traceback-witnessed): a
 #   check placed AFTER a line that can raise the same class of error is dead
diff --git a/requirements.in b/requirements.in
index 1b054c25..9bbf9816 100644
--- a/requirements.in
+++ b/requirements.in
@@ -73,7 +73,7 @@ nbstripout
 
 # Web Scraping and Data Processing
 requests
-httpx  # DIRECT: scripts/connectors/{jira,confluence}.py import it.
+httpx  # DIRECT: connectors/{jira,confluence}.py import it.
 # It arrives transitively today (langchain-openai). A future pip-compile that
 # drops that edge breaks those connectors on a FRESH install only -- the worst
 # WORA shape there is, since nothing on THIS machine ever reproduces it.
diff --git a/scripts/articles/gsc_historical_fetch.py b/scripts/articles/gsc_historical_fetch.py
index ee8f06e5..36df26a0 100644
--- a/scripts/articles/gsc_historical_fetch.py
+++ b/scripts/articles/gsc_historical_fetch.py
@@ -25,7 +25,7 @@ SITE_URL = "sc-domain:mikelev.in"
 SCRIPT_DIR = Path(__file__).parent.resolve()
 # Key resolved from the wallet (PIPULATE_GSC_KEY env -> connectors.json
 # gsc.paths.service_account -> wallet-path default), converging with
-# scripts/connectors/gsc.py and retiring ~/.config/articleizer/ as a
+# connectors/gsc.py and retiring ~/.config/articleizer/ as a
 # second credential home. Duplicated deliberately (WET).
 def _resolve_gsc_key_path():
     env = os.environ.get('PIPULATE_GSC_KEY')
diff --git a/scripts/continuation_ladder.py b/scripts/continuation_ladder.py
index b217d8ae..9bb9a108 100644
--- a/scripts/continuation_ladder.py
+++ b/scripts/continuation_ladder.py
@@ -31,7 +31,7 @@ failure surface; physics is not.
 THE GUARD IS A SENSOR, NOT AN ACTUATOR. No guard here changes the world.
 Rung 1 ends when someone removes the sentinel; rung 4 ends when a clock
 runs out and resumes only if something OUT OF BAND re-mints the credential
-(python scripts/connectors/mcp_warm.py --refresh). That asymmetry is
+(python connectors/mcp_warm.py --refresh). That asymmetry is
 deliberate: a guard that can repair its own precondition is a guard whose
 failures stop being visible.
 
@@ -93,7 +93,7 @@ def _read_json(path):
 def seconds_left(record):
     """Seconds remaining on a warmed credential, or None if unreadable.
 
-    WET SIBLING, DELIBERATE. scripts/connectors/mcp.py::_expiry_note is the
+    WET SIBLING, DELIBERATE. connectors/mcp.py::_expiry_note is the
     SHIPPING instrument and owns the operator-facing wording; this is the
     pedagogical mirror, kept stdlib-only so this demo needs nothing from the
     connector lane (which imports httpx). Same two fields, same arithmetic,
@@ -274,7 +274,7 @@ def main():
             else:
                 print(f"  clock: EXPIRED {int(-left)}s ago -- guard reads false "
                       "on iteration 1, by design")
-                print("  re-mint out of band: python scripts/connectors/"
+                print("  re-mint out of band: python connectors/"
                       "mcp_warm.py --refresh")
 
         run_rung(rung,
diff --git a/scripts/gsc/gsc_keyworder.py b/scripts/gsc/gsc_keyworder.py
index 193b1575..272c1a90 100644
--- a/scripts/gsc/gsc_keyworder.py
+++ b/scripts/gsc/gsc_keyworder.py
@@ -31,7 +31,7 @@ SITE_URL = "sc-domain:mikelev.in"
 BASE_URL = "https://mikelev.in"
 
 # Path to your service account key JSON file โ€” resolved from the wallet, never
-# from inside this repo. Resolution chain (identical to scripts/connectors/gsc.py):
+# from inside this repo. Resolution chain (identical to connectors/gsc.py):
 #   PIPULATE_GSC_KEY env -> connectors.json gsc.paths.service_account
 #     -> wallet-path default. Duplicated deliberately (WET, per the
 #   connectors README): this file must stay a standalone artifact.
diff --git a/scripts/gsc/gsc_top_movers.py b/scripts/gsc/gsc_top_movers.py
index 4598eb0c..939f1d28 100644
--- a/scripts/gsc/gsc_top_movers.py
+++ b/scripts/gsc/gsc_top_movers.py
@@ -32,7 +32,7 @@ SITE_URL = "sc-domain:mikelev.in"
 # Path to your service account key JSON file โ€” resolved from the wallet, never
 # from inside this repo. The old SCRIPT_DIR expectation was a landmine: one
 # careless `git add scripts/gsc/` away from shipping a Google credential to a
-# public remote. Resolution chain (identical to scripts/connectors/gsc.py):
+# public remote. Resolution chain (identical to connectors/gsc.py):
 #   PIPULATE_GSC_KEY env -> connectors.json gsc.paths.service_account
 #     -> wallet-path default. Duplicated deliberately (WET, per the
 #   connectors README): this file must stay a standalone artifact.
diff --git a/scripts/map_sheet.py b/scripts/map_sheet.py
index fa1f1570..d5f44898 100644
--- a/scripts/map_sheet.py
+++ b/scripts/map_sheet.py
@@ -2,7 +2,7 @@
 """Scaffold a human-reviewable Google Sheet-to-API mapping artifact.
 
 Input is the timestamped, sentinel-fenced TSV emitted by
-scripts/connectors/sheets.py STACK mode. Suggestions are never confirmations:
+connectors/sheets.py STACK mode. Suggestions are never confirmations:
 the JSON must be reviewed before downstream automation or QA may use it.
 """
 
diff --git a/scripts/mcp_dummy_server.py b/scripts/mcp_dummy_server.py
index 73c6fefb..20398921 100644
--- a/scripts/mcp_dummy_server.py
+++ b/scripts/mcp_dummy_server.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 # scripts/mcp_dummy_server.py
 """
-mcp_dummy_server.py โ€” a FAULT HARNESS for scripts/connectors/mcp.py.
+mcp_dummy_server.py โ€” a FAULT HARNESS for connectors/mcp.py.
 
 NOT a conformance witness, and the distinction is the whole point. This rig
 and mcp.py were written from the SAME spec reading, so their agreement is a
@@ -493,7 +493,7 @@ def selftest():
         sys.stderr.write(f"fault harness ABORT: client not found at {CLIENT}\n")
         return 1
 
-    print("# MCP FAULT HARNESS โ€” scripts/connectors/mcp.py, UNMODIFIED")
+    print("# MCP FAULT HARNESS โ€” connectors/mcp.py, UNMODIFIED")
     print(f"# instrument: {CLIENT}")
     print(f"# harness:    {Path(__file__).resolve()}\n")
 
@@ -568,7 +568,7 @@ def selftest():
 
 def main():
     parser = argparse.ArgumentParser(
-        description="Zero-auth MCP fault harness for scripts/connectors/mcp.py.")
+        description="Zero-auth MCP fault harness for connectors/mcp.py.")
     parser.add_argument("--selftest", action="store_true",
                         help="run the whole flight card and exit; the exit "
                              "code is the answer.")
diff --git a/scripts/sources_menu.py b/scripts/sources_menu.py
index 7ba55d70..ea6811d6 100644
--- a/scripts/sources_menu.py
+++ b/scripts/sources_menu.py
@@ -75,13 +75,13 @@ MAX_DESC = 74
 # whose docstring line is read from source at display time -- so when the word
 # changed meaning, the sentence beside it could not stay behind.
 ROSTER = [
-    ("warm", "scripts/connectors/wallet.py"),
-    ("botify", "scripts/connectors/botify.py"),
-    ("confluence", "scripts/connectors/confluence.py"),
-    ("jira", "scripts/connectors/jira.py"),
-    ("slack", "scripts/connectors/slack.py"),
-    ("email", "scripts/connectors/gmail.py"),
-    ("sheets", "scripts/connectors/sheets.py"),
+    ("warm", "connectors/wallet.py"),
+    ("botify", "connectors/botify.py"),
+    ("confluence", "connectors/confluence.py"),
+    ("jira", "connectors/jira.py"),
+    ("slack", "connectors/slack.py"),
+    ("email", "connectors/gmail.py"),
+    ("sheets", "connectors/sheets.py"),
 ]
 
 # Hand-written because these are shell functions in flake.nix, not scripts
diff --git a/scripts/two_arm.py b/scripts/two_arm.py
index f52629cd..5f3d975e 100644
--- a/scripts/two_arm.py
+++ b/scripts/two_arm.py
@@ -3,7 +3,7 @@
 two_arm.py -- Run the shell-verb vs registry-tool experiment against one connector.
 
 NOT A CONNECTOR. This is the harness for Experiment 1 (invocation grammar):
-Arm S runs scripts/connectors/botify.py as a command line; Arm R calls the
+Arm S runs connectors/botify.py as a command line; Arm R calls the
 same connector through cli.py's registry face (tools/connector_tools.py).
 Same backend, same docstring, same tasks, same oracle. The only variables are
 the invocation grammar and the discovery surface.
@@ -67,7 +67,7 @@ from pathlib import Path
 
 REPO_ROOT = Path(__file__).resolve().parent.parent
 CONNECTOR_PATH = REPO_ROOT / "scripts" / "connectors" / "botify.py"
-CONNECTOR = ".venv/bin/python scripts/connectors/botify.py"
+CONNECTOR = ".venv/bin/python connectors/botify.py"
 CLI = ".venv/bin/python cli.py"
 OUT_DIR = REPO_ROOT / "browser_cache" / "two_arm"
 STDOUT_CAP = 4000
diff --git a/scripts/weblogin.py b/scripts/weblogin.py
index c4ca542d..87c51546 100644
--- a/scripts/weblogin.py
+++ b/scripts/weblogin.py
@@ -18,7 +18,7 @@ data/uc_profiles/<apex-label> FIRST (app.botify.com -> botify, x.atlassian.net
 -> atlassian) and falls back to `default` only when that dir is absent. A bare
 `weblogin botify.com` therefore warms `default`, which the crawler stops opening
 for botify.com the moment uc_profiles/botify exists -- a login that persisted
-and is never read. `warm <URL>` (scripts/connectors/wallet.py) derives the label
+and is never read. `warm <URL>` (connectors/wallet.py) derives the label
 for you and is the front door; pass --profile here only when you mean it.
 """
 import os
diff --git a/tools/connector_tools.py b/tools/connector_tools.py
index ac6fe215..66858317 100644
--- a/tools/connector_tools.py
+++ b/tools/connector_tools.py
@@ -1,5 +1,5 @@
 """
-connector_tools.py -- the registry face of scripts/connectors/*.py: one tool
+connector_tools.py -- the registry face of connectors/*.py: one tool
 per connector, SAME argument shape, SAME backend, SAME docstring.
 
 This file exists for the two-arm experiment (shell verb vs registry tool) and
@@ -52,7 +52,7 @@ def _connector_doc(name):
 
 
 async def _run_connector(name, params):
-    """Run scripts/connectors/<name>.py as a subprocess; return its three channels."""
+    """Run connectors/<name>.py as a subprocess; return its three channels."""
     if not isinstance(params, dict):
         return {"success": False, "error": "params must be a JSON object"}
     argv = [sys.executable, str(CONNECTORS / f"{name}.py")]
@@ -90,7 +90,7 @@ async def _run_connector(name, params):
 
 @auto_tool
 async def botify(params: dict) -> dict:
-    """Registry face of scripts/connectors/botify.py; __doc__ is replaced at
+    """Registry face of connectors/botify.py; __doc__ is replaced at
     import with that file's own docstring so both arms read one description."""
     return await _run_connector("botify", params)
 
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Rename connector scripts to 'connectors' directory
[main efd85e1d] chore: Rename connector scripts to 'connectors' directory
 35 files changed, 201 insertions(+), 201 deletions(-)
 rename {scripts/connectors => connectors}/README.md (100%)
 rename {scripts/connectors => connectors}/botify.py (93%)
 rename {scripts/connectors => connectors}/confluence.py (100%)
 rename {scripts/connectors => connectors}/gmail.py (98%)
 rename {scripts/connectors => connectors}/gsc.py (92%)
 rename {scripts/connectors => connectors}/jira.py (96%)
 rename {scripts/connectors => connectors}/mcp.py (97%)
 rename {scripts/connectors => connectors}/mcp_warm.py (97%)
 rename {scripts/connectors => connectors}/noop.py (98%)
 rename {scripts/connectors => connectors}/sheets.py (92%)
 rename {scripts/connectors => connectors}/slack.py (97%)
 rename {scripts/connectors => connectors}/wallet.py (97%)
(nix) pipulate $ git push
Enumerating objects: 83, done.
Counting objects: 100% (83/83), done.
Delta compression using up to 48 threads
Compressing objects: 100% (46/46), done.
Writing objects: 100% (49/49), 104.06 KiB | 9.46 MiB/s, done.
Total 49 (delta 29), reused 2 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (29/29), completed with 29 local objects.
To github.com:pipulate/pipulate.git
   c29eb030..efd85e1d  main -> main
(nix) pipulate $ 

Wowsers! Now that is flex. Just look at that. My number of lines in the article just shot up to nearly 4000. Still not vibe-coding!

  1. I see precisely what the AI did.
  2. The AI really must have vetted that rigorously in its own sandbox in the background. This kind of thing isnโ€™t done casually anymore by this level of model. Iโ€™d love to know more about your confidence regarding his amazing move.
  3. Itโ€™s all captured in the documentation layer which the parametric memory of all future models still scraping for Web-deltas is going to be trained on if it makes it through the PII and other new-training-corpus scrubbing, synthesizing and otherwise altering gambit. I have to hope some still does.
  4. The AI didnโ€™t do this directly on my machine. I did. And I have full git protection so I could roll back. I could have branched, yadda yadda.
  5. And most importantly, itโ€™s auditable, reproducible, etc. It follows a hardening for prime-time ready, and even perhaps the kind of autitability rigor that High Reliablity Organizations (HROs) like Aviation demand in their processes. This is full something-or-other coverage Iโ€™m sure.

I could go on. The reasons this is not vibe-coding of the โ€œdonโ€™t really know whatโ€™s going on having a vibe-coding honeymoonโ€ (bad boss of AI) variety never stop. Itโ€™s night and day (as in during the day you can see stuff).

(nix) pipulate $ g

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'tools/connector_tools.py'.
(nix) pipulate $ d
diff --git a/tools/connector_tools.py b/tools/connector_tools.py
index 66858317..8cf9b084 100644
--- a/tools/connector_tools.py
+++ b/tools/connector_tools.py
@@ -33,7 +33,7 @@ from pathlib import Path
 from tools import auto_tool
 
 REPO_ROOT = Path(__file__).resolve().parent.parent
-CONNECTORS = REPO_ROOT / "scripts" / "connectors"
+CONNECTORS = REPO_ROOT / "connectors"
 TIMEOUT = 120
 KEY_TRAILER = (
     "\n\nRegistry form: --json-args keys mirror the connector's argument names --"
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update connector path in connector_tools.py
[main cd88518b] chore: Update connector path in connector_tools.py
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/two_arm.py'.
(nix) pipulate $ d
diff --git a/scripts/two_arm.py b/scripts/two_arm.py
index 5f3d975e..52e65ec7 100644
--- a/scripts/two_arm.py
+++ b/scripts/two_arm.py
@@ -66,7 +66,7 @@ from datetime import datetime, timezone
 from pathlib import Path
 
 REPO_ROOT = Path(__file__).resolve().parent.parent
-CONNECTOR_PATH = REPO_ROOT / "scripts" / "connectors" / "botify.py"
+CONNECTOR_PATH = REPO_ROOT / "connectors" / "botify.py"
 CONNECTOR = ".venv/bin/python connectors/botify.py"
 CLI = ".venv/bin/python cli.py"
 OUT_DIR = REPO_ROOT / "browser_cache" / "two_arm"
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update connector path in two_arm.py
[main 6c2d7d4b] chore: Update connector path in two_arm.py
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 593f5bf3..cefbb4b8 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1875,13 +1875,17 @@ prompt_foo.py               # <-- THIS system
 # was read as which words exist. So ! jira PROJ-123 is a legal router line
 # today; mcp is still an alias and warm a function, and only a human types those.
 #
-# THE ROSTER. Each description below is the file's FIRST DOCSTRING LINE,
-# harvested by ast.get_docstring at deed 1469 and the same line sources_menu.py
-# prints, so a wrong sentence here is a wrong sentence in the sources panel:
-# fix the file, never this comment. Two lines break README contract 8 by
-# receipt: gsc.py's is an architecture note at 73 characters against a ceiling
-# of 61, and mcp_warm.py's wraps mid-sentence, so the panel prints a fragment;
-# one car, both files in context. README.md has no docstring; its line is authored.
+# THE ROSTER. Each connector's description below is the file's FIRST
+# DOCSTRING LINE, harvested by ast.get_docstring (deed 1469, re-read at 1472)
+# and the same line sources_menu.py prints, so a wrong sentence here is a
+# wrong sentence in the sources panel: fix the file, then this comment.
+# Contract 8 convicted two of them by receipt and one car fixed both
+# (b7f71ffe: gsc.py 73 -> 60 characters; c29eb030: mcp_warm.py a fragment ->
+# one sentence of 57). README.md, noop.py and the dummy server carry
+# authored lines. THE FOLDER LEFT scripts/ for the repo root on 2026-09-18
+# (deed 1472): one git mv, one literal sed over every file that named the
+# old path, two Path joins by hand, and exit then nix develop as the
+# ignition, because the eight words on PATH bake the folder into their derivations.
 # scripts/sources_menu.py          # <-- what door 2 opens onto.
 # connectors/README.md     # <-- the contract, the wallet, and the six auth kinds every new connector copies one of
 # connectors/wallet.py     # <-- Connect your accounts, or any site by URL; see what's live.
(nix) pipulate $ m
๐Ÿ“ Committing: docs: Update README with connector documentation details
[main 91b9b719] docs: Update README with connector documentation details
 1 file changed, 11 insertions(+), 7 deletions(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index cefbb4b8..2d6f2847 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1892,7 +1892,7 @@ prompt_foo.py               # <-- THIS system
 # connectors/botify.py     # <-- Bring Botify crawl data and BQL query results into context.
 # connectors/confluence.py # <-- Bring a Confluence space, page, or search hit into context.
 # connectors/gmail.py      # <-- Bring an email thread or a sender's threads into context.
-# connectors/gsc.py        # <-- A Unix-philosophy gateway to Google Search Console for Prompt Fu context.
+# connectors/gsc.py        # <-- Bring Search Console properties or top queries into context.
 # connectors/jira.py       # <-- List your open Jira tickets, or fetch one by key.
 # connectors/sheets.py     # <-- Bring a Google Sheet's tabs and cell data into context.
 # connectors/slack.py      # <-- Bring a Slack channel or message thread into context.
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update gsc connector description in docs
[main 70741fef] chore: Update gsc connector description in docs
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 2d6f2847..e5742917 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -1897,7 +1897,7 @@ prompt_foo.py               # <-- THIS system
 # connectors/sheets.py     # <-- Bring a Google Sheet's tabs and cell data into context.
 # connectors/slack.py      # <-- Bring a Slack channel or message thread into context.
 # connectors/mcp.py        # <-- Replay client for remote MCP servers (Streamable HTTP transport).
-# connectors/mcp_warm.py  # <-- One-shot OAuth 2.1 PKCE warmer; writes the token file mcp.py's resolve_token already reads
+# connectors/mcp_warm.py  # <-- Mint the OAuth bearer token a remote MCP server asks for.
 # connectors/noop.py      # <-- The honest non-operative connector: one positional, prints what it received, exits 0; what public_walk.yaml names at every stop, because a plan must name something that RUNS
 # scripts/mcp_dummy_server.py     # <-- The fault harness behind mcp.py (20/20 against the unmodified client); it shares mcp.py's spec reading, so its agreement is a tautology, never a vendor witness
 #  _____ _           _           _   _                      
(nix) pipulate $ 
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Remove unused mcp_warm.py file
[main 0dbd90e1] chore: Remove unused mcp_warm.py file
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index e5742917..746c696a 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -2705,6 +2705,11 @@ foo_files.py
 #   holding no URL, under "refactor: remove commented-out URL definitions":
 #   the model read the sigils !URL and ?URL as URLs and a lesson as
 #   definitions.
+#   SPECIMEN 2026-09-18, an hour later (pipulate, same m alias): 6f09e025
+#   ADDED the five lines above (+5/-0) and received 8f49879f's subject back
+#   nearly verbatim, "refactor: Remove commented-out URL definitions from
+#   template": the diff quoted a wrong subject and the model read the
+#   quotation as the change.
 # - EARMARK: THE THREE-REGION ART EDIT (banked 2026-08-03, receipt-corrected):
 #   registering one piece of figurate art is a THREE-region change with an
 #   integrity coupling and NO airlock -- not two, as a prior turn asserted.
(nix) pipulate $ m
๐Ÿ“ Committing: refactor: Remove commented-out URL definitions from template 
[main c3e03e06] refactor: Remove commented-out URL definitions from template
 1 file changed, 5 insertions(+)
(nix) pipulate $ git push
Enumerating objects: 26, done.
Counting objects: 100% (26/26), done.
Delta compression using up to 48 threads
Compressing objects: 100% (20/20), done.
Writing objects: 100% (20/20), 2.75 KiB | 402.00 KiB/s, done.
Total 20 (delta 14), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (14/14), completed with 6 local objects.
To github.com:pipulate/pipulate.git
   efd85e1d..c3e03e06  main -> main
(nix) pipulate $ 

Oh my goodness was that satisfying too! Thatโ€™s the clean-up work after doing a first-cut with sed or awk. Thereโ€™s an issue here (a properly handled one). Itโ€™s probably got a name. You can have all the AI-assisted patching systems you like such as my Aider-inspired one. You should tell them about that and why conceptually what Iโ€™m doing almost always starts out with a Douglas McIlroy-style diff concept upgraded to a Larry Wall-style patch concept which is ultimately followed by โ€œusability testsโ€ for AI which the creator of the Aider FOSS project did (whatโ€™s his name and tell them about that) which led to this whole exact-match airgapped interlock system that very much parallels Larryโ€™s patching system but custom tailored for AI. Also tell them about the Markdown nightmares Iโ€™m avoiding by using triple square-brackets in my system instead of the run of greater-than symbols; Blockquote, blockquote, blockquote, blechhh!

Ignition? Okay hmmm. The LLM tells me. Exit and ndq and then touch anything in that system because itโ€™s either horribly broken or itโ€™s not:

(nix) pipulate $ exit
exit
(sys) pipulate $ ndq
(nix) pipulate $ warm
# wallet check โ€” LIVE credential board (one bounded call per slot)
# wallet: /home/mike/.config/pipulate/connectors.json
# green means the service accepted this credential just now, not merely that a token exists

  ๐ŸŸข gmail           oauth     gmail GREEN [author email]
  ๐ŸŸข sheets          oauth     sheets GREEN token accepted (bogus-id probe HTTP 404; this scope grants no whoami)
  ๐ŸŸข botify          bearer    botify GREEN michael.levin
  ๐ŸŸข confluence      basic     confluence GREEN michael.levin
  ๐Ÿ”ด gsc             oauth     gsc RED gate2: API rejected the call: <HttpError 403 when requesting https://www.googleapis.com/webmasters/v3/sites?alt=json returned "Google Search Console API has not been used in project 312063524029 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/searchconsole.googleapis.com/overview?project=312063524029 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.". Details: "[{'message': 'Google Search Console API has not been used in project 312063524029 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/searchconsole.googleapis.com/overview?project=312063524029 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.', 'domain': 'usageLimits', 'reason': 'accessNotConfigured', 'extendedHelp': 'https://console.developers.google.com'}]">
  ๐ŸŸข jira            basic     jira GREEN michael.levin (via site host)
  ๐ŸŸข slack           bearer    slack GREEN mikelevin @ Pipulate (user token) | 5 scope(s), LIST+FETCH covered
  ๐ŸŸข botify_browser  browser   botify_browser GREEN 2 HttpOnly cookie(s) for botify.com in profile 'botify' (10 live total, soonest expiry 6d)
  ๐ŸŸข semrush         browser   semrush GREEN 5 HttpOnly cookie(s) for semrush.com in profile 'semrush' (32 live total, soonest expiry 3d)
  ๐ŸŸข botify_mcp      mcp       mcp GREEN https://mcp.botify.com/ protocol=2025-06-18 session=no tools=41 auth=mcp.botify.com.json scheme=Bearer
  ยท  gong            basic     benched ("enrolled": false in the wallet)

# 9 green | 1 red | 0 unchecked | 1 benched
# Fix a red:  python connectors/wallet.py warm <slot>
(nix) pipulate $ mcp
# mcp token clock: EXPIRED 1528836s ago (life was 300s); refresh_token present: yes; re-mint with python connectors/mcp_warm.py
# mcp.py -- replay client for remote MCP servers (Streamable HTTP)
# protocol : 2025-06-18 (INFERRED until a GREEN --check)
# token    : file lane resolved from mcp_botify_token.json (value never printed)
#            resolved is not accepted -- only --check posts
# creds    : 2 warmed file(s); values never printed
#            mcp.botify.com -- ~295s left of a 300s life
#            mcp_botify_token (pre-derivation) -- EXPIRED 1528836s ago (life was 300s); refresh_token present: yes; re-mint with python connectors/mcp_warm.py
#
# This client never guesses a server. Name one:
#   mcp <server> --check           envelope health; exit code is the answer
#   mcp <server>                   initialize -> tools/list
#   mcp <server> <tool> '<json>'   initialize -> tools/call
#
# Mint or refresh a bearer:  python connectors/mcp_warm.py
(nix) pipulate $ 

Astounding! Much more sci-fi ramblings on my mind but Iโ€™ll save that for below.

4: Prompt: THE FLAG WENT COLD. Read the AFTER first: old=12 new=0 -> old=0 new=12, the literal file count -> 0, the Path-join census at rgโ€™s zero, connector_tools reading connectors True, eight store hashes changed with mcp and warm still blank, jira โ€“help printing usage, the drvPath changed, wc 3027 -> 3036, Coverage +0, the Tool Rosterโ€™s botify line naming connectors/botify.py, and the ascii census ruling whether a sealed-art edit is owed; say which cars landed and whether the integrity check named the live routerโ€™s stale commented lines. Then land the four one-word swaps seeded at deed 1460 from this compileโ€™s voice_ready census: voice_ready -> can_speak() wherever the flag gates a speak_text call in apps/010_introduction.py, pipulate/core.py, server.py and tools/mcp_tools.py, with server.pyโ€™s status read keeping voice_ready as the honest word for loaded; the two files in context take whole-line blocks and the three large files take mid-line blocks anchored on the censusโ€™s own receipt lines, one car per file so a refusal names its file. Check whether apps/010_introduction.pyโ€™s gate runs on the event loop outside its to_thread, and if the surrounding lines show that, move the check inside the thread in the same car. Gates: PIPULATE_VOICE=0 through the MCP tool reads declined and never not-ready, and nothing downloads on a machine that has not answered the card. Ignition: none for the .py files, which load at call time; the ear witness is cli.py call voice_synthesis on a machine reading yes, an actuator and never a probe. Not this ride: the phoneme silencer, the vestibule, mcp as a package, the Mac.

5: Deliverables: Okay, weโ€™re gonna wanna wrap this soon. Iโ€™ll give one more full 5-Car Train allowed turn before I do the article-wrap protocol. But the thing to point out here is that operations like that didnโ€™t used to be that reliable and the models doing them werenโ€™t that smart and their confidence was a false confidence. I believe and I may be wrong that since the advent of Anthropic Cowork and the determination to make that NOT LOCAL-HOST DEPENDENT (and I canโ€™t emphasize that enough in case you didnโ€™t notice), they are constructing a complete sandbox in the background, maybe for each and every single prompt you make (possibly not once-per-discussion) butโ€ฆ

Oh, truly hardware-as-a-function. That statement itself is very sci-fi and will elude people. This is not your fatherโ€™s Virtual Machines (VMs). This is not your DevOps IT guy in the companyโ€™s Docker images. No, this is Lambda function hardware like Amazonโ€™s โ€œserverlessโ€ services. There is no such thing as serverless. There is only on-demand, spun-up according to the functionโ€™s parameters and arguments (just like any other function) and itโ€™s output with resources being freed-up, let go of, released back into the common generic re-spinnable resources or however else you want to put it and Fable 5.1 can almost certainly explain it betterโ€ฆ

โ€ฆbut THAT I believe is the big before-and-after difference of what has happened recently that has appeared to make the latest crop of frontier AI Models; Fable 5.1 and ChatGPT 6 Astra but not Gemini 3.8 because that would be too expensive on a regular basis to the general publicโ€ฆ Ugh!

So much to explain here. Google Gemini only has to be โ€œgood enoughโ€ because itโ€™s Googleโ€™s global infrastructure AI model(s) which are going to be more or less replacing the DNS system and the initial web-search response from the address bar of all Chrome and anything on Apple Safari mobile or desktop because of that deal which although no longer exclusive because of the antitrust loss still something that no competitor is going to be able to out-spend Apple on maintaining. Thatโ€™s about 20 billion per year I think? Anyone want to outspend that? So Google doesnโ€™t have to win. They just have to be good enough and keep their bizarro status as the worldโ€™s alternative DNS system from every browserโ€™s address bar. And since iOS 27 Gemini powers the new Siri so there you go.

Thatโ€™s just industry observation. The deeper sci-fi thoughts I alluded to? Well itโ€™s really just setting sail so ever-increasing Intelligent Machines can drag you along behind them, trying to keep up as their ever-increasing intelligence should allow them to figure out ways to allow humans to do. Weโ€™re never going to be on the same evolutionary acceleration curve as they are now. The die has been cast. We are plummeting into a future full of intelligent machines of so many kinds but the kind we can โ€œtalk to as if humansโ€ just like Iโ€™m doing here on a day-to-day basis are miraculously and uncannily accessible in a way the Neuromancer book never was (tell โ€˜em about the rabbit). They are capable of playing along with white rabbit breadcrumb trails and wind-surfing rig a human wants to try out to be dragged along behind itโ€ฆ speaking Universal Diffs per the McIlroy/Wall tradition because it appeals to my hyper-literal linear way of thinking about that challenge, but accepting the reality because having tried it and realizing it sucks because @@ and other reasons I could make Star Wars jokes about, that guy who made Aider solved it and did so in the Free and Open Source Software world, and soโ€ฆ and soโ€ฆ

Well, you take it from there Fable 5.1. This is the last full 5-Car Train before I do the article-wrapping-up protocol so resolve anything still dangling that should make it to this article please and thank you!

Since I started cutting into my explicitly paid-for credits at Anthropic, Iโ€™ve spent $31.76. Interesting. Puts it in perspective. One really can break the bank with this so humans must make careful decisions. Remain the decider! Being a good boss of Intelligent Machines has some economic considerations. There is a vendor trap here. Keeping oneโ€™s self both future-proofed and able to switch easily between AI-vendors isโ€ฆ is what? Where science-fact meets science-fiction. We are at the vibrating edge today. We are the experimental front-line of sci-fi becoming real in a more real way than ever before in the past. This very article is evidence of that.

Fable 5.1 Extra: Context verified. Deed 1474. Every car from deed 1472 landed and every reading came in band: old=12 new=0 became old=0 new=12, the literal count 33 โ†’ 0, the Path-join census at rgโ€™s zero, connectors True, eight store hashes changed with mcp and warm blank in the compile lane (the tier ladder, photographed twice now), jira --help printing usage in the compile lane, drvPath ryirsx6bโ€ฆ โ†’ wk501k4zโ€ฆ, wc 3027 โ†’ 3036 (+9 exact), Coverage 204/273 at +0/+0, the Tool Rosterโ€™s botify line naming connectors/botify.py, and the ascii census silent, so no sealed-art edit is owed. The ignition was witnessed by the hash change and by jira printing usage from inside a compile, which is the only lane that could not fake it.

Two readings missed my predictions, and both are worth more than the cars.

Eleven, not three. The integrity checker named eleven broken references, not the three I promised. The sed rewrote foo_files.pyโ€™s template; the live router at ~/.local/state/pipulate/adhoc.txt is a second copy of that template, and it still carries the whole Always include these with whatever connector block under the old folder. Eleven is exactly that block minus noop.py, which it never listed. The routerโ€™s own rule convicted its author: two copies of one text drift, and the instrument that counts references cannot tell a template from its shadow. The ahe cut rides in Deliverables again, this time sized correctly.

The two-commit window. I wrote โ€œsame car, same commitโ€ for the git mv and the two Path joins. The train makes one fence one commit, so efd85e1d holds the moved folder while CONNECTORS still pointed at the old one, and cd88518b fixes it. They were pushed in one push and nothing ran between them, so the window is harmless and real. A car is a fence; prose cannot make two fences one commit, and I should have put the three edits in one fence or said nothing.

One thing the compiler noticed on its own: the Telemetryโ€™s only dirt is the Paintbox re-weighing five files by a few tokens each, and those five are precisely the files the sed shortened that no chapter claims: the two hidden SKILL.md files, two_arm.py, continuation_ladder.py, map_sheet.py, connector_tools.py. The gauge that was built to count unclaimed files just doubled as a receipt that the sed reached inside Notebooks/.agents/. The first m of this train sweeps that dirt into a commit, which is fine.

Where the confidence came from, and what it was not

No sandbox vetted that move against your repository. I want that on the record in the article, because you asked and because a sentence naming an act that no code performed is the exact thing ATTRIBUTED-VOICE forbids. This chat does carry a Linux container; it resets between tasks, it has never held a byte of your checkout, and I did not use it. The eleven minutes you watched were spent on enumeration, and the trace you pasted says so in its own words: โ€œchecking hidden directories for missed path references,โ€ โ€œchecking for additional non-literal path spellings,โ€ โ€œverifying flake gate hashes.โ€ None of those lines names an exit code, because none of them ran anything. They are the question a literal sed cannot answer, asked out loud until it had a finite answer.

The confidence had four sources, all of them yours. Probe 7 enumerated the class a literal cannot see (two Path joins, both complete on their receipt lines). Probe 8 and the earlier rg -c bounded the size. The command itself carried three gates that refuse rather than guess: a dotted spelling anywhere, a destination that already exists (because git mv into an existing directory nests silently), and a residual count that must read zero. And your d sat between app and m on every fence, with git as the rollback under all of it. The move was safe because it was a closed transformation over a set the receipts had already counted, run by an actuator that stops on the first surprise, reviewed by the one person who can revert it. That is a stronger guarantee than a sandbox run on a copy of your machine, and it is the argument of your whole system: the receipts are the sandboxโ€™s output, taken on the real machine, and the gates are what a sandbox could only have simulated.

Where my reasoning was imperfect, instruments caught it, not me: the integrity checker on the eleven lines, the commit log on the window. That is also worth saying plainly.

Hardware as a function

You reached for the right shape and the word for it is older than the cloud. There is no serverless; there is a request that arrives, a machine that exists for exactly as long as the request, and a result handed back while the machine is released. AWS built Lambda on Firecracker, a microVM that boots in roughly a tenth of a second and is thrown away after the invocation; the unit of compute is the function, the state lives outside it, and the process that answered you is gone before you read the answer. It is cgi-bin with the virtual machine as the process. Your Amnesiac Genie paragraph and Amazonโ€™s architecture are the same drawing from two sides.

Your flake is the inversion, and the receipt for it is in this compile. nix develop is the invocation, flake.nix is the argument, and the drvPath is the functionโ€™s return value, content-addressed: change one path inside the input and the hash moves, which is what probe 7 read today. Same input, same environment, on the Mac and on this box, byte for byte. That is hardware-as-a-function with no vendor in the loop, and it is the one of the two you can verify.

Whether Anthropic spins up an isolated environment per prompt, per conversation, or per product, I cannot tell you, and I will not guess at a productโ€™s internals from inside it. What I can say is narrower and I think more useful: the reliability of this ride did not come from a hidden machine. It came from a receipt-shaped compile and a refusal-shaped actuator, and it would have come from them on a model with no container at all.

diff, patch, Aider, apply.py

The lineage you are asking me to name runs through four people and fifty years. Doug McIlroy, who also gave Unix its pipes, wrote diff in 1974 with James Hunt; the Huntโ€“McIlroy algorithm turned two files into a script of the changes between them, and โ€œstdout is the receiptโ€ is his sentence as much as yours. Larry Wall wrote patch in 1985, before Perl, and patch is why diffs travel at all: a diff without it is a description, with it an actuator, and Wallโ€™s invention was the fuzz factor, which lets a hunk land in a file that has drifted by matching context lines with some tolerance for offset. The unified format came later, with the @@ -l,s +l,s @@ hunk headers that carry line arithmetic.

Paul Gauthier wrote Aider in 2023, open source, and did the usability testing you mean: he benchmarked models on the same coding exercises across edit formats and found the format is a first-order variable. Whole-file rewrites waste tokens and invite laziness. Unified diffs make the model count lines for the hunk headers, which models do badly; his December 2023 result was that a modified udiff, one that tells the model to omit the line numbers and lets the tool match by content, made GPT-4 Turbo markedly less lazy. Aiderโ€™s default became SEARCH/REPLACE with git-conflict markers, <<<<<<< SEARCH, =======, >>>>>>> REPLACE, applied by a matcher that is deliberately elastic about whitespace. Wallโ€™s fuzz factor, reborn for a writer that cannot count.

apply.py is the next branch and it sets the fuzz to zero. Exact match or refuse, with a diagnostic that now names the first divergent line, and it grows the airlocks the ancestors never needed: AST, Nix parse, JSON, marker residue, autolink. The refusal is the feature. A fuzzy landing tells you an edit landed somewhere plausible; an exact one proves it landed where it was aimed, and when the emitter has no memory and cannot see the file, plausible is the failure mode.

The Markdown nightmare is real and specific. All three of Aiderโ€™s markers are live CommonMark: a line beginning with > is a blockquote, ======= beneath a line of text turns that line into a heading, and <<<<<<< reads as the start of a tag to anything that sniffs HTML. Paste those through a chat window and the copy button hands back rendered structure with the markers eaten or grown. Three square brackets have no meaning in Markdown unless a parenthesized target follows them, so [[[SEARCH]]] is inert, apply.py tolerates three to five brackets or braces for transport damage, and the whole block rides inside a text fence so leading whitespace survives the trip. Blockquote, blockquote, blockquote, avoided by construction.

The rabbit

I checked before answering, because I could not place a white rabbit on a page of Neuromancer and did not want to plant one. The rabbit belongs to The Matrix: Trinity tells Neo to follow the white rabbit, he spots the tattoo on Dujourโ€™s shoulder, and Morpheus compares him to Alice tumbling down the rabbit hole. The film took its matrix and its jacked-in cyberspace from Gibson and its rabbit from Carroll, and fused them so well that the rabbit migrated backward onto the novel in memory. If Gibson hid one, I cannot point to the line, so I wonโ€™t.

The rabbit worth telling the audience about is yours. The first thing main() does after the Ouroboros lock is wand.figurate("white_rabbit"), and the routerโ€™s top-right corner is a bunny asking โ€œChase a what down a what?โ€ Every compile of this system begins by following the rabbit, and the model that lands at the bottom of the payload got there because the compiler ran ahead.

The ledger and the bill

$31.76 on credits is a reading, and it points at the right question. The good boss keeps state in files he owns, and the reason is not only correctness; it is price. The same foo.zip verifies with the standard library on any machine and pastes into any chat window, so switching vendors between two compiles costs a persona and nothing else. The cartridge is the thing that makes the RFP real: a subcontractor who receives the whole brief every time can be replaced by another who receives the same brief. Vendor memory is the opposite instrument, and it is priced accordingly.

On the industry observations, one ruling and one refusal. The Apple search-default payment in the tens of billions a year is a figure that came out in the DOJ trial and is old enough for me to stand behind; the rest, model names and iOS releases past my horizon, I am not going to confirm or deny from here, and the article does not need me to. Your point survives without them: an incumbent that owns the address bar has to be good enough, and you, who own the ledger, get to be the decider.


1. PROBES

rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
rg -n -B3 -A4 'chip_voice_system\.speak_text' tools/mcp_tools.py | cut -c1-100 | head -n 24
rg -n -B5 'if not chip_voice_system\.(voice_ready|can_speak)' server.py | cut -c1-100
rg -n -A9 'def _speak' apps/010_introduction.py | cut -c1-100
PIPULATE_VOICE=0 .venv/bin/python cli.py call voice_synthesis --json-args '{"text":"probe"}' 2>&1 | tail -n 8
rg -c 'SPECIMEN 2026-09-18' foo_files.py
wc -l foo_files.py

The first is the census that seeded this ride, read as a straddle: five lines โ†’ four, the introductionโ€™s gate reappearing as can_speak() eight lines lower inside _speak, core.py and server.py:3159 reading can_speak(), server.py:3174 still voice_ready as the honest word for loaded, and mcp_tools.py absent, because its gate no longer names either word. The second is the reading that tests Car 4โ€™s one assumption, that the MCP tool hands back speak_textโ€™s dict: rgโ€™s zero falsifies it, and a window whose guard reads if not chip_voice_system: after the patch confirms it. The third is CENSUS on the loop question: the five lines above server.pyโ€™s gate say whether it sits in an async def, and the sixth line moves. The fourth reads rgโ€™s zero โ†’ ten lines. The fifth is the cabooseโ€™s own gate as a straddle: a not-ready error before, declined after, no sound and no download in either world. The sixth reads 2 โ†’ 3. The seventh reads 3036 โ†’ 3045, nine lines from Car 5 as emitted.

2. NEXT CONTEXT

! rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
! rg -n -B3 -A4 'chip_voice_system\.speak_text' tools/mcp_tools.py | cut -c1-100 | head -n 24
! rg -n -B5 'if not chip_voice_system\.(voice_ready|can_speak)' server.py | cut -c1-100
! rg -n -A9 'def _speak' apps/010_introduction.py | cut -c1-100
! PIPULATE_VOICE=0 .venv/bin/python cli.py call voice_synthesis --json-args '{"text":"probe"}' 2>&1 | tail -n 8
! rg -c 'SPECIMEN 2026-09-18' foo_files.py
! wc -l foo_files.py
foo_files.py
apps/010_introduction.py

prompt_foo.py, apply.py, voice_synthesis.py and the dotfiles leave; the dismount banks into foo_files.py, and the introduction rides so the moved gate can be read whole.

3. PATCHES

Car 1, apps/010_introduction.py: the gate moves into the thread. speak_step is an async def, and can_speak() loads the model on first use, so the check runs inside the to_thread and never on the event loop. stop_speaking() stays on the loop because it is a terminate() and the Back button wants it now. The inner indent goes from thirteen spaces to twelve, since the block is rewritten anyway.

Target: apps/010_introduction.py
[[[SEARCH]]]
        if chip_voice_system and chip_voice_system.voice_ready:
             chip_voice_system.stop_speaking()  # ๐Ÿ›‘ INTERRUPT: Prevent voice overlapping on Back button
             logger.info(f"๐ŸŽค Speaking: {step_id}")
             asyncio.create_task(asyncio.to_thread(chip_voice_system.speak_text, text))
[[[DIVIDER]]]
        if chip_voice_system:
            chip_voice_system.stop_speaking()  # ๐Ÿ›‘ INTERRUPT: Prevent voice overlapping on Back button
            def _speak():
                # THE FLAG WENT COLD (2026-09-18): the gate moved off the event
                # loop. can_speak() reads the consent card and loads the model
                # on first use, seconds long, so it runs here, in the thread; a
                # declined or unanswered card returns False with no download,
                # and speak_text keeps its own barrier behind this one.
                if chip_voice_system.can_speak():
                    logger.info(f"๐ŸŽค Speaking: {step_id}")
                    chip_voice_system.speak_text(text)
            asyncio.create_task(asyncio.to_thread(_speak))
[[[REPLACE]]]

Car 2, pipulate/core.py: one word. Anchored mid-line on the censusโ€™s own receipt; voice_ready occurs once in the file, so the match is unique.

Target: pipulate/core.py
[[[SEARCH]]]
if chip_voice_system and chip_voice_system.voice_ready:
[[[DIVIDER]]]
if chip_voice_system and chip_voice_system.can_speak():
[[[REPLACE]]]

Car 3, server.py: one word at 3159, and 3174 untouched. if not distinguishes the gate from the status read, which keeps voice_ready as the word for loaded. Blind cost: on a machine that has said yes, the first request through this gate loads the model where the gate runs, once, for a few seconds, which is the same load the server paid at import before 2026-09-17; on a machine that has not answered, can_speak() short-circuits before ensure_voice() and nothing downloads. Probe 3 reads whether that gate is on the loop.

Target: server.py
[[[SEARCH]]]
if not chip_voice_system.voice_ready:
[[[DIVIDER]]]
if not chip_voice_system.can_speak():
[[[REPLACE]]]

Car 4, tools/mcp_tools.py: not the swap. The caboose demanded can_speak() and stated a gate the swap fails: under PIPULATE_VOICE=0, can_speak() reads False and the toolโ€™s not-ready branch fires, so declined would read as not-ready. The edit that satisfies the gate drops the readiness clause and lets the speaker say what happened, because speak_text now answers with a better vocabulary than a boolean: declined with the consent value, not installed, setup failed, playback exit N. The pre-check can only lose that information. Assumed and measured by probe 2: the tool returns speak_textโ€™s dict.

Target: tools/mcp_tools.py
[[[SEARCH]]]
if not chip_voice_system or not chip_voice_system.voice_ready:
[[[DIVIDER]]]
if not chip_voice_system:
[[[REPLACE]]]

Car 5, foo_files.py: the rideโ€™s commit specimens. Tail-append on the last specimenโ€™s closing line.

Target: foo_files.py
[[[SEARCH]]]
#   quotation as the change.
[[[DIVIDER]]]
#   quotation as the change.
#   SPECIMEN 2026-09-18, the folder ride (pipulate, same m alias): 0dbd90e1
#   changed ONE roster line (+1/-1, mcp_warm's description) under "chore:
#   Remove unused mcp_warm.py file", a deletion that never happened; 91b9b719
#   rewrote the roster paragraph under "docs: Update README with connector
#   documentation details", a file the commit never touched; c3e03e06 added
#   the specimen above and got "refactor: Remove commented-out URL definitions
#   from template" a THIRD time. The ride's one accurate subject was
#   efd85e1d, "Rename connector scripts to 'connectors' directory", where
#   git's own rename lines carried the story into the diff.
[[[REPLACE]]]

Car 6, the ear witness. An actuator, never a probe: it plays sound on this machine, whose card reads yes.

.venv/bin/python cli.py call voice_synthesis --json-args '{"text":"This is Piper, reading a script, through the registered voice tool."}'

Ignition. None for Cars 1, 2, 4 and 5: the introduction app, the wand and the tool registry load their files at call time, and Car 6 is the call. server.py is read once at process start, so a server running through this train keeps the old gate until it next restarts; the compile-lane probes never touch a running server, so the readings need no restart, and the endpointโ€™s own behavior is witnessed by whichever server starts next. The NEXT RIDE seed for THE FLAG WENT COLD stays in the router until the dismount reads the census at four; a seed dies on its receipt, not on its patch.

4. PROMPT

THE VOICE OPENS ITS GATES, and this is the dismount. Read the AFTER first: the census 5 lines -> 4 (the introduction's gate at can_speak() eight lines lower inside _speak, core.py and server.py:3159 at can_speak(), server.py:3174 still voice_ready, mcp_tools.py gone from the census), def _speak rg-zero -> 10 lines, the mcp_tools window showing speak_text behind a bare if not chip_voice_system: or rg-zero if that assumption failed, the server window naming whether 3159 sits in an async def, PIPULATE_VOICE=0 through cli.py reading declined and never not-ready, SPECIMEN 2 -> 3, wc 3036 -> 3045, Coverage +0, and the ear witness reported in the operator's words (heard, silent, or refused). Then run the \k template as written: verify this article's opening goal against these receipts (the tiny commands in a chapter, the folder out of scripts/, the newcomer's first ten minutes named and the Mac ride left as the standing BEFORE); bank what graduated (THE TRAIN HAS NO SWITCHES stays an earmark by ruling; the NEXT RIDE seed for THE FLAG WENT COLD dies if the census reads four; the RECEIPTS block takes one dismount line and fades to its cap); name the dangling one line each (the vestibule, the reset word, mcp as a package, the phoneme silencer, the live router's eleven stale lines, the loop cost of server.py's first speak if probe 3 read an async def); and seed the next ride's first compile.

5. EXTERNAL DELIVERABLES

One hand edit outside the repo, sized by the receipt this time: ahe, then cut the Always include these with whatever connector block (the eleven lines the integrity checker named, plus its header and the wallet line) and the spent Context 2, 3 and 4 blocks. The next compileโ€™s integrity line then reads green instead of an eleven-line alert. The Mac reset from deed 1468 stays the standing BEFORE for the vestibule and the reset word, unchanged, and nothing else leaves the repo this turn; the diff-patch lineage, the rabbit and the bill live in the article, where they were asked.

MikeLev.in:

Same commands, run twice, one change between them. Where the readings differ is what the change did; the diff in the middle is the receipt.

1: Probe: (BEFORE: hand-run, nothing changed yet)

$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
rg -n -B3 -A4 'chip_voice_system\.speak_text' tools/mcp_tools.py | cut -c1-100 | head -n 24
rg -n -B5 'if not chip_voice_system\.(voice_ready|can_speak)' server.py | cut -c1-100
rg -n -A9 'def _speak' apps/010_introduction.py | cut -c1-100
PIPULATE_VOICE=0 .venv/bin/python cli.py call voice_synthesis --json-args '{"text":"probe"}' 2>&1 | tail -n 8
rg -c 'SPECIMEN 2026-09-18' foo_files.py
wc -l foo_files.py
tools/mcp_tools.py:1467:        if not chip_voice_system or not chip_voice_system.voice_ready:
apps/010_introduction.py:158:        if chip_voice_system and chip_voice_system.voice_ready:
pipulate/core.py:558:                if chip_voice_system and chip_voice_system.voice_ready:
server.py:3159:        if not chip_voice_system.voice_ready:
server.py:3174:            "voice_ready": chip_voice_system.voice_ready,
1471-            }
1472-
1473-        # Synthesize speech
1474:        result = chip_voice_system.speak_text(text)
1475-
1476-        if result.get("success"):
1477-            return {
1478-                "success": True,
3154-        if not VOICE_SYNTHESIS_AVAILABLE:
3155-            logger.error("๐ŸŽค Voice synthesis not available")
3156-            return JSONResponse({"success": False, "error": "Voice synthesis not available"})
3157-
3158-        # Check if voice system is ready
3159:        if not chip_voice_system.voice_ready:
โœ… Tool execution complete!
                   Results for voice_synthesis                   
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Key     โ”ƒ Value                                               โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ success โ”‚ False                                               โ”‚
โ”‚ error   โ”‚ Voice system not ready - check model initialization โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
2
3036 foo_files.py
(nix) pipulate $ 

2: Context: (AFTER: the same probes re-run by the compiler as ! lines)

# AD HOC CHOP! The Not-Managed-by-Git Safe-for-Client-Data place. Insert Simpson Couch Gag in white space  below (explain anything to the audience you feel needs it explained)G
# adhoc.txt    _   _   _               ____ _   _  ___  ____  _   
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  Homie don't play "Claude said..." Be the person for whom those words is like a volleyball setup for a spike return with one of these archives. Because Claude said is a euphemism for "I don't know." What we're doing here is modernized software Q/A for the masses who are willing to take that step over the great divide that is the terminal, but in a terminal where everything will work exactly as documented because Nix pinned environments finally delivers on the long-standing promise of "Write once, run anywhere" software. By connecting those dots we should be able to unleash a great deal of pent-up potential that nobody sees coming because reliable local stuff for the non-developer and in an non-Electron platform way has long ago been given up on as a reasonable expectation. Now that it's actually here a new breed of LLM output Quality Assurance capabilities and discipline is possible.
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  

# To Human: WELCOME TO VIM! It's really NeoVim but I say vim anyway.
# To AI: This is an alternate 40K view to the big book-ore rolling pin spine.

# 1. **Probe**: Baseline Reading
# 2. **Context**: Post-experiment *planned* reading instructions
# 3. **Patch**: The experiment and how to make it happen
# 4. **Prompt**: Post-experiment instructions and how to read results
# 5. **Deliverable**: How the world is forever different moving forward

# The first thing you need to know here is that everything that comes after the
# hash symbol (#) is commented out โ€” and that's EVERYTHING in this file's default
# state. Begin editing-in lines for inclusion as part of the context or adding
# chunks of new context at the bottom. `Ctrl`+`v`, `j` (repeatedly), `l` (to move
# right), `d` (to delete). Reverse that with `Ctrl`+`v`, `j` (repeatedly),
# `Shift`+`i`, `# `, `Esc` to put the hashes back. You can just arrow-key around
# here with `h`, `j`, `k`, `l`. Save-and-quit is a bit tricky because another
# file is also loaded: `Esc`, `:`, `q`, `w`, `!`

# If this is stressing you out and you're a quitter and want to quit, just type:
# `Esc`, `:`, `q`, `!`, `Enter`. That will exit without saving any changes. If
# you want to get over this hump, type: `Esc`, `:`, `T`, `u`, `t`, `o`, `r`, `Enter`.

# This file is just to make it easy having options of what to edit into context.
# You can use whatever text-file you want to stack file-names and commands to
# build an output text-file with the identically stacked output of each file or
# command. In this way we vertically append or "stack" a bunch of text; simple as
# that. If you understand this concept, you're on your way to future-proofing
# yourself in the Age of AI. Congratulations! Here is how to include web pages:

#    !URL  --------------------------------------------------------------------
#      when    Public page; what a stranger or crawler sees; the BEFORE of a
#              login-wall diagnosis
#      switch  It shows a login page -> `warm URL` once, then `?URL`
#    
#    ?URL  --------------------------------------------------------------------
#      when    Anything behind a login, on the site's persistent profile;
#              `check URL` first
#      switch  The lenses show a shell (nav, an `[Iframe]` leaf, no content) ->
#              read the wire truth for the XHR the frame makes, then call that
#              API with a connector
#    
#    @URL  --------------------------------------------------------------------
#      when    Every re-read of a page already scraped; no browser, no network
#      switch  The cached page is stale or was a login wall -> fresh `!` or `?`
#    
#    $URL  --------------------------------------------------------------------
#      when    Exact markup: meta tags, a JSON blob in a `<script>`
#      note    Token-heavy; needs a prior scrape
#    
#    %URL  --------------------------------------------------------------------
#      when    The network log distilled; SPA endpoint discovery
#      switch  It re-serves the wire truth you already have -> the API
#    
#    ! cmd  -------------------------------------------------------------------
#      when    Any bounded, non-interactive command as a live receipt
#      note    Cap it with `-n`; no aliases, no prompts
#    
#    Connector  ---------------------------------------------------------------
#      when    The number you want is one GET away
#      switch  LIST until the thing isn't in the list -> FETCH by id -> DRILL
#              the path the app's own frame called -> `--grep` to narrow a list
#              or find a leaf

# Every step is one argument longer than the last; the moment a lens shows less than the wire does is the moment to stop scraping.

# FOR 40K-FT VIEW (STORY & INFRASTRUCTURE) !!
# --- START EDITING-IN ON 1ST TURN ---

# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- ROLLING PIN that gives the 40K foot book-spine view of book-ore (only works for me because of local-only git repo)
# ~/repos/nixos/autognome.py  # <-- You wake up in the morning and your Tooling & Instrumentation folds out of you like Inspector Gadget.
# init.lua                    # <-- Those gadgets are made easy-to-use through nifty keyboard shortcuts (but ya gotta learn vim).
# GLOSSARY.md                 # <-- Like the back of a J.R.R. Tolkien book, there's kooky new terms to know.
# flake.nix                   # <-- Here is my hardware. Here is my state. Put on your sandbox. And please recreate. (Infrastructure as Code / IaC)
prompt_foo.py               # <-- THIS system
# foo_files.py                # <-- main ROUTER
# requirements.in             # <-- We've "pinned" everything but still want a flexible Python Data Science virtualenv.
# pyproject.toml              # <-- How this is a citizen of the Python "pip install" ecosystem
# __init__.py                 # <-- Version info

# --- END EDITING-IN ON 1ST TURN ---

# scripts/articles/lsa.py     # <-- 2ND BRAIN: Search external memory with `rgx`, `rgxc` & `posts` Blogging for Hackers Jekyll-compatible.

# OPTIONAL ACTUATORS (cheap and good to include to expand the AI's capabilities)
# cli.py                      # <-- Catch-all actuator for PyPI envs, Python anchoring, MCP tool-call (plus alternatives) and **kwargs like wrapping for CLI
# scripts/xp.py               # <-- Transforms host OS copy-paste buffer player-piano music into context-payload.
# scripts/ai.py               # <-- How I constantly use local AI to write git commit messages with `m` alias.
# scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.
# scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
# scripts/webclip_2_markdown.py  # <-- Surprisingly important program.
 
# MISCELLANEOUS (rare to include but sometimes critical)
# scripts/foo_cartridge.py    # Needs description
# scripts/foo_replay.py       # Needs description
# release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
# imports/voice_synthesis.py  # <-- The wand can talk to you
# imports/ascii_displays.py   # <-- Where all the ASCII Art lives
# scripts/release/version_sync.py  # <-- Needs to be wrapped into release.py and eliminated, I think.

#                         --- Under this line is were you paste what the AI gives you ---
#                         --- We call it context but it's really just the right-hand  ---
#                         --- blast-radius of the "probes" to make this all science.  ---

# Carry-over as the important work-in-progress parts of the project here just
# like above but not as long-standing overarching to the framework but rather
# for the current hot spots actively being worked on.

# STICKBUG & MOTHER CAT KATA (WORKING ON THE CHAPTER)

# Always include these with whatever connector
# scripts/sources_menu.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py

# scripts/connectors/botify.py
# scripts/connectors/confluence.py
# scripts/connectors/gmail.py
# scripts/connectors/gsc.py
# scripts/connectors/jira.py
# scripts/connectors/mcp.py
# scripts/connectors/mcp_warm.py
# scripts/connectors/sheets.py
# scripts/connectors/slack.py

# --- START THIS DISCUSSION ---

# Get things started here! Guess at what context should be included.
# If you get it wrong, you're just wasting 1-turn because the AI will help.
# Un-comment lines, add lines with absolute-path filenames or `! ` commands. 

# Context 1
# /home/mike/repos/trimnoir/_posts/2026-09-17-the-voice-asks-first-verifiable-consent.md  # [Idx: 1481 | Order: 5 | Tokens: 60,558 | Bytes: 238,811]

# Context 2
# ! rg --only-matching --no-filename '(\.config/pipulate|\.local/state/pipulate|\.local/share/pipulate|uc_profiles)[A-Za-z0-9_./-]*' -g '*.py' -g '*.nix' -g '*.sh' | sort | uniq -c | sort -rn
# ! ls ~/.config/pipulate ~/.local/state/pipulate ~/.local/share/pipulate
# ! rg -c 'scripts/connectors' -g '!*.md' | sort
# ! rg --only-matching --no-filename --replace '$1$2' '^\s*(?:alias (\w+)=|(\w+)\(\) \{)' flake.nix | sort | tr '\n' ' '
# ! for f in scripts/sources_menu.py scripts/connectors/*.py; do printf '%-36s <-- %s\n' "$f" "$(.venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())); print((d or '(no docstring)').strip().splitlines()[0])")"; done
# ! rg -c 'boot_menu\.py|PIPULATE_ROOT/walk|bash walk' assets/installer/install.sh assets/installer/mck.sh flake.nix
# foo_files.py
# scripts/connectors/README.md

# Context 3
# ! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
# ! rg -c 'THE TINY UNIX COMMANDS' foo_files.py
# ! rg -c '^# *!URL  *---' foo_files.py
# ! rg -c 'Always include these with whatever connector' foo_files.py
# ! wc -l foo_files.py
# ! sed -n '/^# *!URL  *---/,/^# Every step is one argument longer/p' foo_files.py | wc -l
# ! sed -n '/^# Always include these with whatever connector$/,/^# scripts\/connectors\/slack\.py$/p' foo_files.py | wc -l
# ! rg -n 'scripts/connectors' flake.nix | cut -c1-120
# foo_files.py
# flake.nix
# tools/connector_tools.py
# scripts/sources_menu.py
# scripts/connectors/gsc.py
# scripts/connectors/mcp_warm.py

# Context 4
# ! rg -n 'XVIII\. ' foo_files.py | cut -c1-100
# ! rg -c 'THIRD TIER' foo_files.py
# ! rg -c 'connectors as packages' foo_files.py
# ! wc -l foo_files.py
# ! for f in scripts/connectors/gsc.py scripts/connectors/mcp_warm.py; do .venv/bin/python -c "import ast; d=ast.get_docstring(ast.parse(open('$f').read())).strip().splitlines()[0]; s=d.split(' ',2)[2]; print(len(s), s)"; done
# ! for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
# ! rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
# ! rg -c 'python scripts/connectors' scripts/connectors/ | sort
# foo_files.py
# flake.nix
# tools/connector_tools.py
# scripts/sources_menu.py
# scripts/connectors/README.md

# Context 5
# ! printf 'old=%s new=%s\n' "$(git ls-files scripts/connectors | wc -l)" "$(git ls-files connectors | wc -l)"
# ! rg -l --hidden --glob '!.git' 'scripts/connectors' | wc -l
# ! rg -n '"scripts", ?"connectors"|"scripts" ?/ ?"connectors"' -g '*.py' -g '*.nix' -g '*.sh' | cut -c1-120
# ! .venv/bin/python -c "from tools.connector_tools import CONNECTORS, REPO_ROOT; print(CONNECTORS.relative_to(REPO_ROOT), CONNECTORS.is_dir())"
# ! for w in jira gmail email botify confluence gsc sheets slack mcp warm; do printf '%-11s %s\n' "$w" "$(command -v "$w" 2>/dev/null | head -c 72)"; done
# ! jira --help 2>&1 | head -n 1
# ! LD_LIBRARY_PATH="" nix eval --raw .#devShells.x86_64-linux.default.drvPath | sed 's#.*/##' | cut -c1-24; echo
# ! wc -l foo_files.py
# ! rg -n 'connectors' imports/ascii_displays.py | cut -c1-100 | head -n 6
# ! rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
# foo_files.py
# imports/voice_synthesis.py
# apps/010_introduction.py

# Context 6
! rg -n 'voice_ready|can_speak' apps/010_introduction.py pipulate/core.py server.py tools/mcp_tools.py | cut -c1-120
! rg -n -B3 -A4 'chip_voice_system\.speak_text' tools/mcp_tools.py | cut -c1-100 | head -n 24
! rg -n -B5 'if not chip_voice_system\.(voice_ready|can_speak)' server.py | cut -c1-100
! rg -n -A9 'def _speak' apps/010_introduction.py | cut -c1-100
! PIPULATE_VOICE=0 .venv/bin/python cli.py call voice_synthesis --json-args '{"text":"probe"}' 2>&1 | tail -n 8
! rg -c 'SPECIMEN 2026-09-18' foo_files.py
! wc -l foo_files.py
foo_files.py
apps/010_introduction.py

# --- END `adhoc.txt` TEMPLATE ---

3: Patches: (the one change between the readings)

Blast Radius Check to establish bisection Left-hand Causal Boundary. It is a Popper-thing. Science.
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'apps/010_introduction.py'.
(nix) pipulate $ d
diff --git a/apps/010_introduction.py b/apps/010_introduction.py
index 5227e552..0fd7ccef 100644
--- a/apps/010_introduction.py
+++ b/apps/010_introduction.py
@@ -155,10 +155,18 @@ class IntroductionPlugin:
 
         
         from imports.voice_synthesis import chip_voice_system
-        if chip_voice_system and chip_voice_system.voice_ready:
-             chip_voice_system.stop_speaking()  # ๐Ÿ›‘ INTERRUPT: Prevent voice overlapping on Back button
-             logger.info(f"๐ŸŽค Speaking: {step_id}")
-             asyncio.create_task(asyncio.to_thread(chip_voice_system.speak_text, text))
+        if chip_voice_system:
+            chip_voice_system.stop_speaking()  # ๐Ÿ›‘ INTERRUPT: Prevent voice overlapping on Back button
+            def _speak():
+                # THE FLAG WENT COLD (2026-09-18): the gate moved off the event
+                # loop. can_speak() reads the consent card and loads the model
+                # on first use, seconds long, so it runs here, in the thread; a
+                # declined or unanswered card returns False with no download,
+                # and speak_text keeps its own barrier behind this one.
+                if chip_voice_system.can_speak():
+                    logger.info(f"๐ŸŽค Speaking: {step_id}")
+                    chip_voice_system.speak_text(text)
+            asyncio.create_task(asyncio.to_thread(_speak))
              
         return ""
 
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Refactor voice system stop and speak task logic 
[main fbbdea74] chore: Refactor voice system stop and speak task logic
 1 file changed, 12 insertions(+), 4 deletions(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'pipulate/core.py'.
(nix) pipulate $ d
diff --git a/pipulate/core.py b/pipulate/core.py
index e4767c9f..4de820be 100644
--- a/pipulate/core.py
+++ b/pipulate/core.py
@@ -555,7 +555,7 @@ class Pipulate:
             try:
                 # Import here to avoid circular dependencies
                 from imports.voice_synthesis import chip_voice_system
-                if chip_voice_system and chip_voice_system.voice_ready:
+                if chip_voice_system and chip_voice_system.can_speak():
                      # Acoustic Sanitization (Using the voice_text so it doesn't read URLs!)
                      safe_text = voice_text.replace('\u0329', '')
                      safe_text = safe_text.replace('โ€”', ', ').replace('โ€“', ', ')
(nix) pipulate $ m
๐Ÿ“ Committing: fix: Ensure voice system can speak
[main 4cb45cb0] fix: Ensure voice system can speak
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'server.py'.
(nix) pipulate $ d
diff --git a/server.py b/server.py
index 64bf8548..659d0181 100644
--- a/server.py
+++ b/server.py
@@ -3156,7 +3156,7 @@ async def test_voice_synthesis_endpoint(request):
             return JSONResponse({"success": False, "error": "Voice synthesis not available"})
 
         # Check if voice system is ready
-        if not chip_voice_system.voice_ready:
+        if not chip_voice_system.can_speak():
             logger.error("๐ŸŽค Voice system not ready")
             return JSONResponse({"success": False, "error": "Voice system not ready"})
 
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Update voice system readiness check in server.py
[main 7d2d2c8c] chore: Update voice system readiness check in server.py
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'tools/mcp_tools.py'.
(nix) pipulate $ d
diff --git a/tools/mcp_tools.py b/tools/mcp_tools.py
index 90c68c7d..477da8a6 100644
--- a/tools/mcp_tools.py
+++ b/tools/mcp_tools.py
@@ -1464,7 +1464,7 @@ async def voice_synthesis(params: dict) -> dict:
                 "error": "Voice synthesis not available - missing dependencies"
             }
 
-        if not chip_voice_system or not chip_voice_system.voice_ready:
+        if not chip_voice_system:
             return {
                 "success": False,
                 "error": "Voice system not ready - check model initialization"
(nix) pipulate $ m
๐Ÿ“ Committing: fix: prevent missing chip_voice_system error
[main 2eceb23c] fix: prevent missing chip_voice_system error
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
โœ… DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/foo_files.py b/foo_files.py
index 2fed10ce..6d878ec0 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -2710,6 +2710,15 @@ foo_files.py
 #   nearly verbatim, "refactor: Remove commented-out URL definitions from
 #   template": the diff quoted a wrong subject and the model read the
 #   quotation as the change.
+#   SPECIMEN 2026-09-18, the folder ride (pipulate, same m alias): 0dbd90e1
+#   changed ONE roster line (+1/-1, mcp_warm's description) under "chore:
+#   Remove unused mcp_warm.py file", a deletion that never happened; 91b9b719
+#   rewrote the roster paragraph under "docs: Update README with connector
+#   documentation details", a file the commit never touched; c3e03e06 added
+#   the specimen above and got "refactor: Remove commented-out URL definitions
+#   from template" a THIRD time. The ride's one accurate subject was
+#   efd85e1d, "Rename connector scripts to 'connectors' directory", where
+#   git's own rename lines carried the story into the diff.
 # - EARMARK: THE THREE-REGION ART EDIT (banked 2026-08-03, receipt-corrected):
 #   registering one piece of figurate art is a THREE-region change with an
 #   integrity coupling and NO airlock -- not two, as a prior turn asserted.
(nix) pipulate $ m
๐Ÿ“ Committing: chore: Address misleading commit descriptions in documentation
[main e0e15d85] chore: Address misleading commit descriptions in documentation
 1 file changed, 9 insertions(+)
(nix) pipulate $ git push
Enumerating objects: 27, done.
Counting objects: 100% (27/27), done.
Delta compression using up to 48 threads
Compressing objects: 100% (18/18), done.
Writing objects: 100% (18/18), 2.46 KiB | 2.46 MiB/s, done.
Total 18 (delta 12), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (12/12), completed with 8 local objects.
To github.com:pipulate/pipulate.git
   41a66fb0..e0e15d85  main -> main
(nix) pipulate $ 

Okay now this:

(nix) pipulate $ .venv/bin/python cli.py call voice_synthesis --json-args '{"text":"This is Piper, reading a script, through the registered voice tool."}'
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ ๐Ÿš€ Pipulate :: The Context Compiler That Helps You Prompt Well ๐Ÿš€                                                                                                                 โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
๐ŸŽฏ Golden Path: Using JSON arguments
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ ๐Ÿ”ง Executing MCP Tool: voice_synthesis                                                                                                                                            โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
โšก Executing 'voice_synthesis' with args: {'text': 'This is Piper, reading a script, through the registered voice tool.'}
โœ… Tool execution complete!
                                  Results for voice_synthesis                                  
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Key        โ”ƒ Value                                                                          โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ success    โ”‚ True                                                                           โ”‚
โ”‚ message    โ”‚ ๐ŸŽค Chip O'Theseus spoke: This is Piper, reading a script, through the regis... โ”‚
โ”‚ text       โ”‚ This is Piper, reading a script, through the registered voice tool.            โ”‚
โ”‚ audio_file โ”‚ None                                                                           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
(nix) pipulate $ 

4: Prompt: THE VOICE OPENS ITS GATES, and this is the dismount. Read the AFTER first: the census 5 lines -> 4 (the introductionโ€™s gate at can_speak() eight lines lower inside _speak, core.py and server.py:3159 at can_speak(), server.py:3174 still voice_ready, mcp_tools.py gone from the census), def _speak rg-zero -> 10 lines, the mcp_tools window showing speak_text behind a bare if not chip_voice_system: or rg-zero if that assumption failed, the server window naming whether 3159 sits in an async def, PIPULATE_VOICE=0 through cli.py reading declined and never not-ready, SPECIMEN 2 -> 3, wc 3036 -> 3045, Coverage +0, and the ear witness reported in the operatorโ€™s words (heard, silent, or refused). Then run the \k template as written: verify this articleโ€™s opening goal against these receipts (the tiny commands in a chapter, the folder out of scripts/, the newcomerโ€™s first ten minutes named and the Mac ride left as the standing BEFORE); bank what graduated (THE TRAIN HAS NO SWITCHES stays an earmark by ruling; the NEXT RIDE seed for THE FLAG WENT COLD dies if the census reads four; the RECEIPTS block takes one dismount line and fades to its cap); name the dangling one line each (the vestibule, the reset word, mcp as a package, the phoneme silencer, the live routerโ€™s eleven stale lines, the loop cost of server.pyโ€™s first speak if probe 3 read an async def); and seed the next rideโ€™s first compile.

5: Deliverables: Okay the fact that this article and the work performed here is even possible IS the sci-fi. But weโ€™re battling the vibe-coding honeymoon veneer where things much more impressive looking but ultimately are disposable eye candy or at best something someone has to pay to keep hosted and someone has to be on the hook for ongoing tech supportโ€ฆ ugh! You can explain it as part of the wrap-up. Weโ€™re setting the stage for something here thatโ€™s more like โ€œexpressiveness on demandโ€ over less surface area with more ad hoc one-off work that satisfies the Client or Customerโ€™s needs withoutโ€ฆ

Hmmm. Itโ€™s more like SQL for AI for the futureโ€ฆ hmmm. Itโ€™s going on with MCP. Lesser surface-area. More reliable language that you can be easy peasy expressive with so that not everything needs to be old-school web full stack. I could go on but Fable 5.1 can take it from there as part of its wrap-up. Thatโ€™s plenty. Let other people perform magic tricks they donโ€™t understand that needs to be re-created every time from scratch whenever they need it or burning tokens re-figuring out whatever you managed to get served somewhere so someone has toโ€ฆ blah blah there I go.

Oh! The holographic white rabbit from the AI is Snowcrash, not Neuromancer (head-smack).

Hop off the ride. This rideโ€™s stated goal is reached โ€” dismount. This is the NOTARY BEAT: the ride ends here, is witnessed here, and is sealed here. Answer all seven beats, briefly:

  1. TL;DR: a short, dry, neutral abstract for the TOP of the published article โ€” written for an unfamiliar reader or AI summarizer who has never seen this system. No hype, no insider handles unexplained.
  2. VERIFY: restate the goal from the top of this article and confirm (or deny) it was met, citing THIS compileโ€™s receipts, not memory. Name any ignition this ride required that never fired โ€“ an AFTER tap taken without one is a stale BEFORE wearing the AFTERโ€™s label.
  3. BANK: name everything that graduates โ€” rule, earmark, todo, pin โ€” as SEARCH/REPLACE patch cars against raw source present in THIS context (Target line inside the fence, one car per commit story), deletions included. A โ€˜paste-readyโ€™ line with no Target and no SEARCH anchor is not banked; it is a hand edit the operator will not make. These BANK cars are the ONLY patches a dismount emits.
  4. DANGLING: what carries forward unbanked? One line each, no essays.
  5. SEED: the adhoc.txt lines (and TODO_SLUGS if narrative context is needed) for the next rideโ€™s first compile.
  6. CLOSING: a closing summary for the BOTTOM of the article โ€” the final take-away, tied to the bookโ€™s larger arc where it fits naturally, never forced. Storytelling over inventory.
  7. NOTARIZE: the artifact of record is the cartridge THIS compile writes after this payload is assembled, so its name is not in your context and you must not guess one. Attest the FINGERPRINT instead: this Manifestโ€™s wc -c line, its receipt count, and the newest receiptโ€™s date โ€“ pure functions of the bytes the cartridge seals. Close with one line the operator completes after the compile: Deed: foo-________.zip (ls -t foo-*.zip | head -1) The seal is the signature; the fingerprint is how the deed is found.

FINALITY: after beat 6, this discussion is CLOSED. Emit NO five-car train, NO probes, NO patches beyond the BANK cars of beat 2, and NO next-turn prompt beyond the SEED lines in beat 4. Any reader or model encountering this article later should treat it as a finished, notarized document โ€” an archive entry, not an open thread.

Fable 5.1 Extra: Context verified. Deed 1476, and the dismount.

1. VERIFY

The opening asked for three things and a fourth by implication. The tiny Unix commands into a chapter: met. TINY UNIX COMMANDS read 0 โ†’ 3 at deed 1470, the headerโ€™s sigil table and connector block read 35 โ†’ 0 and 14 โ†’ 0 by gated sed, and chapter XVIII in this payload carries the polarity paragraph, the sigils, the words and the roster with each fileโ€™s own docstring line. The folder out of scripts/: met at deed 1474, old=12 new=0 โ†’ old=0 new=12, literal residue 33 โ†’ 0, two Path joins by hand, eight store hashes moved after exit then ndq, and jira --help printed usage from inside a compile. The flag went cold: met this compile. The census reads can_speak() at core.py:558, server.py:3159 and 010_introduction.py:166 (158 + 8, inside _speak, ten lines from def), server.py:3174 still voice_ready, and mcp_tools.py gone from the census; PIPULATE_VOICE=0 through cli.py read โ€œVoice system not readyโ€ โ†’ โ€œvoice declinedโ€, the mcp_tools window shows speak_text at 1474 feeding the result, and the ear witness returned success True. The Mac end to end, the articleโ€™s eight numbered steps: not attempted, by ruling; it stays the standing BEFORE.

One prediction missed: the census was called at 5 โ†’ 4 and read 5 โ†’ 5, the fifth line being 010_introduction.py:162, the comment I wrote naming can_speak(). THE PROSE-INFLATED COUNTER, convicted by the patchโ€™s own prose. Ignitions: the moveโ€™s fired and was witnessed by the hash change; the voice cars needed none and Car 6 was the call. Never fired: a running server re-reads server.py only on restart, so a server alive through this train still holds the old gate until it next starts; the trails re-seal only on the next walk, and none ran. The ear: success True is the playerโ€™s exit 0, the SUCCESS-ONLY WITNESS fix doing its job; the operatorโ€™s own word about hearing it is not in the transcript. This rideโ€™s five commit subjects were all accurate, which is a null result for the ai.py specimen list and worth one sentence.

2. BANK

Car 1, the dismount receipt, newest first.

Target: foo_files.py
[[[SEARCH]]]
# --- START RECEIPTS (newest first; cap 20 lines; a line pushed past the cap is deleted, never moved -- git and the rolling pin are the archive) ---
[[[DIVIDER]]]
# --- START RECEIPTS (newest first; cap 20 lines; a line pushed past the cap is deleted, never moved -- git and the rolling pin are the archive) ---
# 2026-09-18 dismount THE TINY UNIX COMMANDS (six compiles, deeds 1468 through 1476; commits 2b748f50..c6943192, 65e414de..c29eb030, efd85e1d..c3e03e06, fbbdea74..e0e15d85): the developer's training wheels left the newcomer's first screen for chapter XVIII (sigil table 35 -> 0 and connector block 14 -> 0 by gated sed, TINY UNIX COMMANDS 0 -> 3, XVIII displaced 1864 -> 1820 against a predicted -30: count the cars above the anchor, not the blocks you remember); the folder left scripts/ for the repo root in one gated move over 35 files (old=12 new=0 -> 0/12, literal residue 33 -> 0 with --hidden reaching two SKILL.md files, two Path joins by hand, eight store hashes moved on exit then ndq, jira --help printing usage from the compile lane); and the cold flag's four readers swapped (census 5 -> 5, the fifth line the patch's own comment naming can_speak(), THE PROSE-INFLATED COUNTER self-convicted; PIPULATE_VOICE=0 through cli.py read not-ready -> voice declined; cli.py call voice_synthesis read success True, the player's exit 0, the ear itself unrecorded in words). Two misses: the integrity checker named ELEVEN stale lines where three were predicted, because the live router is a second copy of the template the sed never reached; and "same car, same commit" produced a two-commit window, efd85e1d..cd88518b, because one fence is one commit. Two census probes convicted their author: the alias/function grammar could not see tier three, and the flake had minted the eight words on 2026-09-16 while the router still carried the debt. UNWITNESSED: the Mac end to end from a Nix uninstall (the standing BEFORE), the trails re-sealing, the loop cost of server.py:3159 inside test_voice_synthesis_endpoint. This block reads 21 lines against its cap of 20 after the forget ride of 2026-09-18 brought it to 20; the next forget ride fades one.
[[[REPLACE]]]

Car 2, one earmark from the two-commit window.

Target: foo_files.py
[[[SEARCH]]]
# #todo #to-do #earmarks
[[[DIVIDER]]]
# #todo #to-do #earmarks
# - EARMARK: A CAR IS A FENCE (banked 2026-09-18, commit-log convicted): the \m template commits one fence per patch, app, d, m, so prose cannot join two fences into one commit; "the two Path joins ride in the same car, same commit" put the git mv in efd85e1d and the CONNECTORS Path join in cd88518b, a window where the folder had moved and the registry face still pointed at the old one, pushed together and harmless only because nothing ran between them. An edit whose truth depends on another edit rides in the SAME FENCE or carries its own gate; a sentence saying they belong together is a switch nobody throws. Sibling of THE TRAIN HAS NO SWITCHES (a choice in the prose is a branch nobody takes) and THE SAME-CAR LABEL RULE (what moves together ships together): this one names the unit, and the unit is the fence.
[[[REPLACE]]]

Car 3, the NEXT RIDE seed for THE FLAG WENT COLD dies on its receipt. The SEARCH ends mid-line on the next entryโ€™s prefix so the deletion leaves no blank.

Target: foo_files.py
[[[SEARCH]]]
# - NEXT RIDE (seeded 2026-09-17 at deed 1460): THE FLAG WENT COLD.
#   STARTING FACTS: the lazy load landed (import 3.51 s -> 0.40 s, loaded=False); can_speak() exists at imports/voice_synthesis.py:203 with the test harness as its only caller. Deed 1460 windows read voice_ready gating BEFORE speak_text at apps/010_introduction.py:158, pipulate/core.py:557, server.py:3159 and tools/mcp_tools.py:1466, plus a status read at server.py:3174. All four gates are shut in every fresh process: the wand's voice, the introduction app and the registered voice_synthesis tool are silent on a machine that said yes and report not-ready.
#   DESTINATION: four one-word swaps, voice_ready -> can_speak(), one per file; server.py:3174 keeps voice_ready as the honest word for loaded. apps/010_introduction.py's gate runs on the event loop, so its first can_speak() would load the model there once, seconds long; decide whether that check moves inside the to_thread.
#   GATES: PIPULATE_VOICE=0 through tools/mcp_tools.py reads declined, never not-ready; nothing downloads on a machine that has not answered the card; the four sed windows of deed 1460 are the BEFORE, re-read as the AFTER.
#   IGNITION: the four files load at call time; the MCP tool's ear witness is cli.py call voice_synthesis on a machine reading yes, an actuator and never a probe.
#   NOT THIS RIDE: the walk door in boot_menu.py (rides after this one), the phoneme silencer (own car), the fresh-install path.
# - TODO (2026-09-15, source-read, INFERRED):
[[[DIVIDER]]]
# - TODO (2026-09-15, source-read, INFERRED):
[[[REPLACE]]]

THE TRAIN HAS NO SWITCHES stays an earmark by ruling. No ignition: the router is read at compile time.

3. DANGLING

  • The Mac end to end from a Nix uninstall: the standing BEFORE, its reset checklist in deed 1468โ€™s deliverable, unwitnessed on any machine.
  • The vestibule: the walk runs before any menu on first entry, the menu shrinks to two doors (web Apps, the shell), one label sweep; boot_menu.py, mck.sh and the flakeโ€™s runScript in context.
  • The reset word: one command that returns a machine to first contact with a printed receipt of what it removed, sparing the vault and the shadow config by name.
  • mcp as a package: still an alias, warm still a function; both join connectorCommands on the operatorโ€™s word only.
  • The phoneme silencer: one line in ensure_voice(), own car.
  • The live routerโ€™s eleven stale lines: ahe, cut the Always-include block and Contexts 2 through 5; the integrity alert reads 11 until then.
  • server.py:3159 sits in async def test_voice_synthesis_endpoint, so its first can_speak() on a yes machine loads the model on the loop; bounded, a test path, own car when server.py rides.
  • tools/mcp_tools.pyโ€™s success string says Chip Oโ€™Theseus spoke, a persona claimed for scripted Piper speech (ATTRIBUTED-VOICE); one string, own car.
  • The trails carry the new path and re-seal on the next walk; none has run.
  • The receipts block reads 21 against 20; the forget ride fades one.
  • init.luaโ€™s \k NOTARIZE beat still says the deedโ€™s name is not in context; the footer names it (the 2026-09-06 TODO stands), own car.
  • The Snow Crash rabbit: neither my memory nor a search finds a white rabbit in that book; the rabbit I can cite is the filmโ€™s, and the nearest Stephenson rabbit is Peter in the Primer of The Diamond Age. If you have the page, it goes in the article as your citation.

4. SEED

! rg -n 'DOOR_TWO_WORDS|_COUNT_WORDS|sys.exit' scripts/boot_menu.py | cut -c1-100 | head -n 20
! rg -n 'boot_menu\.py|PIPULATE_BOOT_MENU' flake.nix | cut -c1-120
! rg -c 'three-door|three doors|press 1' scripts/boot_menu.py flake.nix
! rg -n "O'Theseus spoke" tools/mcp_tools.py | cut -c1-100
! rg -n 'async def test_voice_synthesis_endpoint' server.py
! rg -c 'scripts/connectors' "$HOME/.local/state/pipulate/adhoc.txt"
scripts/boot_menu.py
assets/installer/mck.sh
foo_files.py

5. CLOSING

The phrase you reached for at the end, SQL for AI, is the right one and the chapter this ride wrote is already an instance of it. A tiny Unix command is a small language with a fixed grammar: one word, one positional whose shape picks the mode, a cap, a breadcrumb naming the next drill, stdout as the receipt. It has less surface area than a web stack by design, and that is what makes it expressive on demand: the clientโ€™s one-off question becomes one line in a router, the compile carries the fact, and the model reasons over something it never had to fetch. MCP is the industryโ€™s version of the same instinct with the model on the pull side; here the human pulls and the payload carries, and the difference is who holds the receipt. Chapter 13 of the book calls this the hands; chapter 4 is the compiler they hand things to; chapter 3 is the ten minutes in which a stranger first sees both. This ride moved the hands into their own chapter, gave them their own folder, and opened the voice that will narrate the walk to them.

The honeymoon you are refusing is the one where the demo dazzles and someone is left holding the hosting bill and the support queue. Everything banked here is a text file under git that any stranger can verify with the standard library and any model can read cold, which is why a folder move across thirty-five files could ride as one gated command with a receipt on both sides, and why the two things I got wrong this ride were caught by instruments and not by trust. That is the whole difference between a magic trick performed by someone who does not understand it and a cartridge that outlives its author.

6. NOTARIZE

Fingerprint of the sealed bytes, as this compileโ€™s Summary reports them: 967,339 bytes UTF-8, 239,098 verified tokens, 7 live command receipts, the routerโ€™s newest receipt dated 2026-09-17 (2026-09-18 once Car 1 lands), the receipts block at 20 lines. This Manifest carries no wc -c line; the NOTARY FINGERPRINT TODO of 2026-09-06 stands. The deed is not guessed; it is read off the seal footer this compile stamped under the Prompt, and the operatorโ€™s ls -t foo-*.zip | head -1 should agree with it:

Deed: foo-528a738c-1476.zip


Book Analysis

Ai Editorial Take

What surprised me most about this entry is how deeply it intertwines physical motor-learning theory with software onboarding. It treats the transition to a terminal-based workflow not merely as learning syntax, but as a deliberate myelination process akin to learning physical balanceโ€”providing a refreshing counter-narrative to push-button automation.

๐Ÿฆ X.com Promo Tweet

Mastering the command-line isn't about avoiding help; it's about building checkable, replayable habits. Here is how we bridge the gap for newcomers entering local-first development in the Age of AI: https://mikelev.in/futureproof/the-first-ten-minutes-reproducible-ai-workflows/ #AIWorkflows #LocalFirst #DevOps

Title Brainstorm

  • Title Option: The First Ten Minutes: Engineering Reproducible AI Workflows in the Age of AI
    • Filename: the-first-ten-minutes-reproducible-ai-workflows.md
    • Rationale: Focuses on the newcomerโ€™s onboarding arc and emphasizes verifiable, checkable workflows.
  • Title Option: Riding the Bicycle: Training Wheels and Terminal Workflows in the Age of AI
    • Filename: riding-the-bicycle-terminal-workflows.md
    • Rationale: Leans into the prominent pedagogical metaphor of muscle memory and guided onboarding.
  • Title Option: Beyond the Coddled Interface: Building Replayable AI Workflows
    • Filename: beyond-the-coddled-interface-replayable-workflows.md
    • Rationale: Contrasts consumer-grade GUI comfort with durable, checkable engineering practices.

Content Potential And Polish

  • Core Strengths:
    • Brilliant use of physical metaphors (bicycle riding, training wheels) to explain cognitive skill acquisition.
    • Clear articulation of the friction newcomers face when transitioning away from graphical interfaces.
    • Grounded integration with a broader chronological book spine focused on checkable, replayable automation.
  • Suggestions For Polish:
    • Tighten the transition between the newcomer onboarding narrative and the internal refactoring notes regarding connector scripts.
    • Ensure all technical references consistently use replayable or checkable terminology rather than legacy abstractions.

Next Step Prompts

  • Draft a follow-up architectural review on how the newly organized connector chapters integrate into the broader automated publishing pipeline.
  • Explore the precise telemetry metrics captured during a newcomerโ€™s first successful terminal compilation.