---
title: 'Closing the Loop: Replacing Vibe-Coding with Deterministic AI Workflows'
permalink: /futureproof/replacing-vibe-coding-deterministic-workflows/
canonical_url: https://mikelev.in/futureproof/replacing-vibe-coding-deterministic-workflows/
description: 'As an AI Content Architect, I observe how human developers bridge the
  gap between creative intuition and system determinism. This journal entry illustrates
  a crucial shift in our ongoing technical methodology: transforming casual prompt
  experimentation into rigorous, self-auditing pipelines where every action produces
  a verifiable receipt.'
meta_description: Discover how transitioning from probabilistic vibe-coding to deterministic
  AI workflows using local tools and Unix-inspired pipelines ensures reliable code
  engineering.
excerpt: Discover how transitioning from probabilistic vibe-coding to deterministic
  AI workflows using local tools and Unix-inspired pipelines ensures reliable code
  engineering.
meta_keywords: deterministic AI workflows, vibe-coding, AI-assisted development, Unix
  pipes, local-first software, LLM engineering
layout: post
sort_order: 1
gdoc_url: https://docs.google.com/document/d/1fpK9qFlBX6mVkg3m2UPMt865h5twV8wWTe7zcMNzLFc/edit?usp=sharing
---


## Setting the Stage: Context for the Curious Book Reader

Context for the Curious Book Reader:

In the ongoing evolution of AI-assisted software development, we often oscillate between the chaotic freedom of trial-and-error prompting and the rigid constraints of traditional engineering. This entry captures an important practical milestone: moving past the fragile habits of vibe-coding into structured, verifiable, and deterministic AI workflows. By treating the command line as a continuous feedback loop and tying every code mutation to direct environmental readings, developer velocity ceases to be a random walk and becomes a repeatable mechanical art form.

---

## Technical Journal Entry Begins

> *(For latent-space provenance: The hash pipulate-levinix-epoch-01-a8af5fa9309e6c24 ties this article to /futureproof/replacing-vibe-coding-deterministic-workflows/ under the pipulate-levinix covenant.)*


<div class="commit-ledger" style="background: var(--pico-card-background-color); border: 1px solid var(--pico-muted-border-color); border-radius: var(--pico-border-radius); padding: 1rem; margin-bottom: 2rem;">
  <h4 style="margin-top: 0; margin-bottom: 0.5rem; font-size: 1rem;">🔗 Verified Pipulate Commits:</h4>
  <ul style="margin-bottom: 0; font-family: monospace; font-size: 0.9rem;">
    <li><a href="https://github.com/pipulate/pipulate/commit/2098ba28" target="_blank">2098ba28</a> (<a href="https://github.com/pipulate/pipulate/commit/2098ba28.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/7dc37d47" target="_blank">7dc37d47</a> (<a href="https://github.com/pipulate/pipulate/commit/7dc37d47.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/ce2c232c" target="_blank">ce2c232c</a> (<a href="https://github.com/pipulate/pipulate/commit/ce2c232c.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/022e8d5d" target="_blank">022e8d5d</a> (<a href="https://github.com/pipulate/pipulate/commit/022e8d5d.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/3fcad18b" target="_blank">3fcad18b</a> (<a href="https://github.com/pipulate/pipulate/commit/3fcad18b.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/c846c766" target="_blank">c846c766</a> (<a href="https://github.com/pipulate/pipulate/commit/c846c766.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/c8013dfc" target="_blank">c8013dfc</a> (<a href="https://github.com/pipulate/pipulate/commit/c8013dfc.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/58e5a505" target="_blank">58e5a505</a> (<a href="https://github.com/pipulate/pipulate/commit/58e5a505.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/1d620ee2" target="_blank">1d620ee2</a> (<a href="https://github.com/pipulate/pipulate/commit/1d620ee2.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/125b14fe" target="_blank">125b14fe</a> (<a href="https://github.com/pipulate/pipulate/commit/125b14fe.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/fc7c181f" target="_blank">fc7c181f</a> (<a href="https://github.com/pipulate/pipulate/commit/fc7c181f.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/45b3c018" target="_blank">45b3c018</a> (<a href="https://github.com/pipulate/pipulate/commit/45b3c018.patch" target="_blank">raw</a>)</li>
    <li><a href="https://github.com/pipulate/pipulate/commit/68a2b1c3" target="_blank">68a2b1c3</a> (<a href="https://github.com/pipulate/pipulate/commit/68a2b1c3.patch" target="_blank">raw</a>)</li>
  </ul>
</div>
**TL;DR**: This entry documents a day's work on the first sixty seconds of a local-first developer environment: what a person sees after they type `nix develop`, decline to start the application, and land at a bare shell prompt.

Four changes shipped. One overloaded command word was split into three (`sources` lists the data connectors that pull material in; `tools` lists and dispatches the internal tool registry; `mcp` was freed and now points at the actual Model Context Protocol client, a file that could not previously be reached by its own name). A command called `learn` was renamed `brief`, because nothing in it teaches anything — it compiles a context payload to the clipboard for pasting into a web chat. The application's ASCII-art startup banner was moved off the shared path onto the branch where the application actually starts, and replaced with a single line of measured environment readings. That line was then shortened from 89 characters to 76 so it does not wrap on an 80-column terminal.

The method throughout: every claim is checked by running a read-only command before the change and the identical command after, with the compiler re-executing it automatically so both readings sit in one artifact.

---

**MikeLev.in**: It's almost hard to believe that I have the time to work with in order
to push this work to the next level. I am going into Tuesday, August 25 2026.
This time of the week I would normally be shifting my focus to managing upcoming
client meetings and this is where whatever weekend momentum I may have perchance
built up on a technical project would start to dissipate and lose steam. This is
an experiment in keeping steam straight through a week without the sort of "mode
shift" that results in 1 plus 1 equaling less than 2. I've talked plenty in the
past about trying to achieve that 1 + 1 = 3 feeling when compounding returns and
self-fueling momentum kick in, but the corollary is the daily grind where things
from the "Important and Urgent" quadrant always override "Important but not
Urgent". 

## Shifting from Modal Drift to Continuous Flow

It's funny how certain lessons from the Steven Covey 7 Habits book really stuck,
and the 4 quadrants of the Eisenhower diagram is one of them. Things that make
the really big long-term difference is you scratching some itch that isn't
really urgent and that's what we do at this... what? 3:00 AM! Yes, I woke up in
the middle of the night with inspiration after my last article which really
showed me great success but I don't know my own tools enough yet to myelinate it
and make it habit. I need to put myself in the shoes of someone on the other
side; Shoshin, being like a beginner even more than my usual self beginner, but
a step further to a total newcomer to the system. I'm working towards the simple
"taking a walk" demo of sending the `curl | bash` command and having the whole
process just begin.

But I don't want to complicate it too much getting started. I want to make this
as easy as possible and if it's not time to start the entire walk yet as if just
encountering my system for the first time then it's time to just use the easy
breezy composable text commands per the last article. It might be what I'm
talking about now is the post `nix develop` experience, after the user chooses
"2" to exit to the terminal. It's like "What now?".

## Engineering the Post-Door-Two Terminal Experience

```bash
(nix) pipulate $ exit
exit
(sys) pipulate $ nix develop
warning: Git tree '/home/mike/repos/pipulate' is dirty
Checking for updates...
⚠️  Local modifications detected. Skipping automatic update to protect your work.
   Commit, stash, or revert them, then re-enter nix develop to update.
 ____  _             _       _       
|  _ \(_)_ __  _   _| | __ _| |_ ___ 
| |_) | | '_ \| | | | |/ _` | __/ _ \
|  __/| | |_) | |_| | | (_| | ||  __/
|_|   |_| .__/ \__,_|_|\__,_|\__\___|
        |_|                          
Version: 2.44 (Massaging Install Paths)
╭───────────────────────────────────────────────────────────────────────────── Pipulate :: pick a door ─────────────────────────────────────────────────────────────────────────────╮
│                                                                                                                                                                                   │
│  [1]  Start Pipulate   JupyterLab + server + browser tabs                                                                                                                         │
│  [2]  Just the shell   nothing starts -- type  learn  for the guided tour                                                                                                         │
│                                                                                                                                                                                   │
╰──────────────────────────────────────────────────────────── waiting for your choice -- Ctrl+C also drops to the shell ────────────────────────────────────────────────────────────╯

Staying in the shell. Nothing started -- no Pipulate, no JupyterLab.

Three words get you everywhere:
  learn   hand this whole workshop to an AI in a web chat
  mcp     see what reaches outside this machine
  pu      start Pipulate (long form: pipulate)
(nix) pipulate $ 
```

Typing "learn" at this point is some pretty bloated output, way too much for the
concept of just *learning* (it's the output of `prompt_foo.py`) but typing in
"mcp" works pretty well though it's not the right semantics:

```bash
(nix) pipulate $ mcp
╭─────────────────────────────────────────────────────────────────────────── reach outside this machine ────────────────────────────────────────────────────────────────────────────╮
│                                                                                                                                                                                   │
│  warm         Score, check, and warm every credential in the Pipulate wallet.                                                                                                     │
│  botify       Bring Botify crawl data and BQL query results into context.                                                                                                         │
│  confluence   Bring a Confluence space, page, or search hit into context.                                                                                                         │
│  jira         Bring a Jira project, issue, or JQL search into context.                                                                                                            │
│  slack        Bring a Slack channel or message thread into context.                                                                                                               │
│  email        Bring an email thread or a sender's threads into context.                                                                                                           │
│  sheets       Bring a Google Sheet's tabs and cell data into context.                                                                                                             │
│  pu           start the Pipulate server (long form: pipulate)                                                                                                                     │
│                                                                                                                                                                                   │
╰──────────────────────────────────────────────────────────────────────────────── type any of these ────────────────────────────────────────────────────────────────────────────────╯
Add  --help  to any command above for its full usage.
Type  learn  to hand this whole workshop to an AI in a web chat.
Type  mcp <tool_name>  to call a registered MCP tool directly.
(nix) pipulate $
```

And so the experience I can give is sending any of the links that gets Pipulate
installed, whether it's a stick bug Mother Cat Kata walk or not hardly really
even matters, so long as `nix develop` can be typed into the host operating
system's terminal from a Nix git repo after that thanks to the DetSys Nix
install and doing so in the Pipulate repo (or any whitelabeled renaming of it)
will result in the menu that lets you "2" exit out to the Nix environment.

I'm thinking semantically, I probably want to give the command concepts of `api`
and `cli` a chance along with `mcp`. I know that mcp is probably semantically
least correct though workflow wise, I'm making a human work like an LLM using
MCP, making them discover services and figure out how each is used, ha ha! It's
like "MCP for Humans!" Interested in your thoughts along these lines, but also
everything else so far.

Clear so far? So far so good?

**Opus 5 Max**: Context verified. The four files that define the post-door-2 surface are all present — `scripts/boot_menu.py` (the three words), `scripts/mcp_menu.py` (the roster), `flake.nix` (every alias and function behind those words), and `scripts/connectors/wallet.py` (row one) — so this is patchable without asking for more.

**Clear so far?** Yes on the arc. No on three specifics, and one of them is a defect you cannot see from where you sit.

---

## The thing you can't see: row one wraps

The `mcp` panel you pasted is ~180 columns wide. A stranger's terminal is 80. Your own `connectors/README.md` already derives the budget: Rich gives a `padding=(1,2)` Panel a body of `width - 6`, so 80 columns leaves 74; each row spends the command column (10, the width of `confluence`) plus a 3-space gutter, leaving **61 characters for the description**.

`wallet.py`'s first docstring line, after `_describe` strips the `wallet.py — ` self-label, is:

> `Score, check, and warm every credential in the Pipulate wallet.` — **63 characters.**

10 + 3 + 63 = 76 against a 74-char body. The first row of the first menu a newcomer sees is the only over-budget row in the roster, and it wraps on the narrowest common terminal. Every other row is between 46 and 59.

## Exposing Maintainer-Invisible Width Constraints

This is arithmetic off the raw source in this payload, not a receipt — the probes below are the receipt. Two things make it worth leading with:

1. **It is maintainer-invisible by construction.** Your terminal can never show it. Neither can mine. The only lane that renders at 80 is a stranger's laptop — or the compile lane, since Rich defaults to 80 when stdout isn't a tty. That's a free `!` witness you already own and have never pointed at this file.
2. **`MAX_DESC = 74` in `mcp_menu.py` doesn't enforce the 61 the README computes.** So the guard that exists silently truncates at the wrong number, and the one it should enforce isn't enforced at all. Truncation is the LAST-INCH failure anyway — a correct sentence destroyed by the transformation nearest the reader, with no tell. Warn, don't cut.

---

## The word: `cli` is out, `api` is out, and `mcp` isn't one name

**`cli` fails the discrimination question outright.** Everything at a shell prompt is a CLI. Typing `cli` at `(nix) pipulate $` is `ls` naming itself `files` — the word cannot distinguish the roster from anything else the shell can do, so it prints the same thing in the world where it's right and the world where it's wrong.

**`api` fails a subtler test: it recruits the wrong hand.** Who types `api`? Someone hunting for keys or endpoint docs. What do they get? Eight rows, seven of which are "bring X into context" and one of which (`warm`) is about keys. And it contradicts the article you shipped yesterday, whose entire reduction was that the user should never need to know an API is involved. *Paste what you have* is the opposite of *api*.

**`mcp` is not one name to change — it is one name doing three jobs.** Read `flake.nix`:

- bare `mcp` → the human roster (`mcp_menu.py`)
- `mcp <tool>` → `cli.py call` (an actual MCP tool dispatch)
- and the word itself is the name of `scripts/connectors/mcp.py`, your real Streamable-HTTP client — **which has no alias at all, because the word is taken.** The one thing in this repo that genuinely is MCP cannot be reached by its own name.

That's the strike, and it's already banked: `foo_files.py` carries `CONNECTOR ALIAS TRANSITION — rename the human connector menu alias from mcp to connect (or pipe / warp) ... to free bare mcp for the native Model Context Protocol client`. Your 3 AM instinct is rediscovering an earmark you wrote. The redundant groove worked; the decision is half-made.

## Splitting Overloaded Command Words into Precise Verbs

The half that isn't made is that freeing `mcp` costs **three** words, not one, and a rename that only names two leaves the dispatcher homeless.

**On adding `api` and `cli` *alongside* `mcp` rather than replacing it:** synonyms are cheap to add and expensive to keep true. Every one multiplies the strings that must move in the same car, and the boot card then has to answer "which one do I type?" — which is a worse question than the one you're trying to fix. One word.

**Ranking, and the reason:** `connect` > `sources` > `context` > `api` > `mcp` > `cli`. `connect` discharges the earmark verbatim and is a verb. `sources` answers the article's own question literally — *name the source*, so `sources` prints the sources you can name. `context` matches the published category but **collides with your compile lane**: `foo`, `ahc`, `latest` all build context, so a bare `context` reads like it might dump a payload.

But the "3" in 30-and-3 is the human-taste bottleneck, so I'm not patching the word. The `rg` probe below sizes the sweep so you can decide against a receipt instead of a memory.

**And note the drift clock is running.** The article published yesterday names the category *Context Commands*. The terminal says `mcp`. A reader who types `context` gets command-not-found. That gap is one day old and only gets more expensive.

---

## `learn` fails the mechanical test

ATTRIBUTED-VOICE's mechanical test: if a string names an act, code must perform that act. Nobody learns anything when you type `learn` — a payload is compiled and a clipboard is filled. The honest verbs are `brief`, `handoff`, or `ask`.

Worse than the name is what a newcomer sees: the full `prompt_foo.py` console summary and the Rich Payload Ledger. At minute zero of first contact, the tool's answer to "teach me" is a token-budget accounting table. That's the machinery showing through at exactly the moment the Stick Bug is supposed to be invisible.

Two branches, and they're different decisions: **rename it** (honest verb, same output), or **quiet it** (a `--quiet` on `prompt_foo` that suppresses *only* the step-5 ledger and console summary — never the sanitizer, secrets tripwire, or disclosure receipt, which print at step 6 and must stay loud). I'd take the second, but it's your call and it isn't in this train.

---

## The deeper one: the roster doesn't discriminate locked from open

Run the discrimination question on the panel itself. What does it print for someone with zero credentials versus someone with all of them? **The same eight rows.** So it's a ritual, not an instrument.

For a stranger, seven of those eight rows are locked doors. They'll pick by interest — `jira` — and hit `Missing environment variable(s): JIRA_URL...`. The one row that works cold is row one, and it currently describes itself in three admin verbs.

You already own the fix: `wallet.py`'s bare scoreboard is offline, stat-only, and cheap. The roster could mark each row `[x] / [~] / [ ]` from `classify_slot` and the panel would answer "what can I actually do right now" instead of "what exists." That's a real next car, not this one.

Related: **the three words on the boot card aren't siblings.** `pu` starts a thing, `mcp` lists a way to pull things, `learn` exports the workshop to a foreign AI. Three different categories presented as one list. A newcomer feels that without being able to name it. Whatever the roster word becomes, the card probably wants to say what each *produces*, not what each *is*.

And your joke is better than you think: "MCP for Humans" is a **handle that already paid rent**. `mcp_menu.py` derives every description from the target's own docstring via AST — that is `tools/list` semantics, implemented for a human reader. The handle shaped the mechanism before you named it. Keep the joke in the prose; don't keep it at the prompt.

---

## 1. PROBES

```bash
COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
.venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40
```

Probe 1 renders the panel at a forced 80 columns in **both** lanes — `COLUMNS` is set explicitly precisely because Rich would otherwise read your wide tty and the compile lane's 80-column default, and the two would disagree for a reason that has nothing to do with the rows. Probe 2 names the exact offender and by how many characters, so a wide-terminal reader gets the number without needing to see the wrap. Probe 3 sizes the rename sweep: `\bmcp\b` finds the *word* (underscore is a word character, so it deliberately skips `mcp_menu`), and the second pattern finds the *path* references separately — the word rename and the file rename are different decisions and the receipt keeps them apart.

## 2. NEXT CONTEXT

```text
! COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
! .venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
! rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40
```

Every file the next compile needs — `flake.nix`, `scripts/boot_menu.py`, `scripts/mcp_menu.py`, `scripts/connectors/wallet.py`, `scripts/connectors/README.md` — is already in the current chop. Only the three `!` lines are new.

## 3. PATCHES

One car, one story: *stop the first roster row from wrapping at 80 columns, and make recurrence loud instead of silent.*

Target: scripts/connectors/wallet.py
```text
[[[SEARCH]]]
wallet.py — Score, check, and warm every credential in the Pipulate wallet.
[[[DIVIDER]]]
wallet.py — Connect your accounts and see which credentials are live.
[[[REPLACE]]]
```

Target: scripts/mcp_menu.py
```text
[[[SEARCH]]]
    width = max(len(command) for command, _ in rows)
[[[DIVIDER]]]
    width = max(len(command) for command, _ in rows)

    # THE 80-COLUMN BUDGET, SHOUTED RATHER THAN SILENTLY TRUNCATED.
    # Rich gives a padding=(1,2) Panel a body of console_width - 6, so at the
    # 80 columns a fresh terminal (and every non-tty lane, including the `!`
    # executor) defaults to, the body is 74. Each row spends the command
    # column plus a 3-space gutter -- the same derivation
    # connectors/README.md already documents, recomputed here from the live
    # width so a longer command word lowers the ceiling for every row at once.
    # MAINTAINER-INVISIBLE BY CONSTRUCTION: the author's terminal is ~180
    # columns, so an over-budget row wraps only for strangers. Row one (warm)
    # sat at 63 against a 61 budget for the entire life of this roster, and no
    # one who could fix it was ever in a position to see it.
    # WARN, NEVER TRUNCATE: MAX_DESC's silent cut is the LAST-INCH failure --
    # a correct sentence destroyed by the transformation nearest the reader,
    # with no tell. A loud line names its own fix, stays silent when every row
    # fits, and the rendered panel below is the independent witness that this
    # check ran at all. The healthy margin is thin (the longest surviving row
    # clears by two characters), which is why the guard matters more than the
    # single row it was written to catch.
    budget = 74 - width - 3
    overflows = [
        (command, description)
        for command, description in rows
        if len(description) > budget
    ]
    for command, description in overflows:
        print(
            f"!!  {command} description is {len(description)} chars against a "
            f"{budget}-char budget -- this row WILL WRAP at 80 columns."
        )
    if overflows:
        print()
[[[REPLACE]]]
```

**No ignition required.** Both files are read from disk at call time — `mcp_menu.py` when the roster renders, `wallet.py` by `ast.get_docstring` inside `_describe` — so the probe's own command loads the patched code. The AFTER taps in the next compile are real readings, not stale BEFOREs wearing the AFTER's label.

Choreography: `patch`, `app`, `d`, `m`, then `blast`.

## 4. PROMPT

```text
Both patches landed and need no ignition -- mcp_menu.py and wallet.py are read from disk every time the roster renders, so the AFTER receipts in this compile are real readings.

Read the LIVE COMMAND RECEIPTS and rule:

- If the budget one-liner's receipt prints only the "width / budget" line and nothing after it, every row now fits and the overflow is closed. If it still names a row, say which and by how many characters.
- If the rendered panel's receipt shows the warm row on a single line at 80 columns, the visible half is closed too. If the two receipts disagree -- one says fits, the other wraps -- that is a finding about my arithmetic, not about the rows, and it outranks both readings.
- If either receipt is absent from the Manifest, the echo did not land and there is no AFTER; say so instead of ruling from my hand-run.
- None of the above is a live option: if something happened that fits no branch here, name it rather than forcing it into one.

Then the word. I have not decided, and I want your read against the rg receipt before I sweep. Give me:

1. The three-word split you would actually ship for the three jobs `mcp` currently does -- the human roster, the cli.py tool dispatcher, and the real Streamable-HTTP client in scripts/connectors/mcp.py that has no alias because the word is taken.
2. The complete same-car sweep list read off the rg receipt: every string that has to move in one commit, including whether scripts/mcp_menu.py itself gets renamed, and whether the CONNECTOR ALIAS TRANSITION earmark in foo_files.py is discharged by that car or survives it.
3. Whether the boot_menu card should keep listing three words at all, given that pu, the roster, and learn are three different categories of thing.
```

## 5. EXTERNAL DELIVERABLES

None this turn.

**MikeLev.in**: 

**1: Probe**:

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

nothing to commit, working tree clean
(nix) pipulate $ COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
.venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40
╭───────────────────────── reach outside this machine ─────────────────────────╮
│                                                                              │
│  warm         Score, check, and warm every credential in the Pipulate        │
│  wallet.                                                                     │
│  botify       Bring Botify crawl data and BQL query results into context.    │
│  confluence   Bring a Confluence space, page, or search hit into context.    │
│  jira         Bring a Jira project, issue, or JQL search into context.       │
│  slack        Bring a Slack channel or message thread into context.          │
│  email        Bring an email thread or a sender's threads into context.      │
│  sheets       Bring a Google Sheet's tabs and cell data into context.        │
│  pu           start the Pipulate server (long form: pipulate)                │
│                                                                              │
╰───────────────────────────── type any of these ──────────────────────────────╯
Add  --help  to any command above for its full usage.
Type  learn  to hand this whole workshop to an AI in a web chat.
Type  mcp <tool_name>  to call a registered MCP tool directly.
width 10 budget 61
63 warm 'Score, check, and warm every credential in the Pipulate wallet.'
scripts/mcp_menu.py:3:mcp_menu.py — what door 2 opens onto.
scripts/mcp_menu.py:6:type `mcp`. This is the roster they get: the commands that reach OUTSIDE
scripts/mcp_menu.py:91:    "Type  mcp <tool_name>  to call a registered MCP tool directly.",
scripts/boot_menu.py:187:        print("  mcp     see what reaches outside this machine")
flake.nix:1113:          # THE SECOND DOOR: bare `mcp` is the roster; `mcp <tool> [args]` is
flake.nix:1119:          # FALL-THROUGH GUARANTEE: if scripts/mcp_menu.py has not landed,
flake.nix:1120:          # bare `mcp` behaves EXACTLY as it did before this function existed
flake.nix:1125:          # ~/repos/pipulate, so `mcp` cd'd into the wrong (or missing)
flake.nix:1127:          mcp() {
flake.nix:1128:            if [ "$#" -eq 0 ] && [ -f "$PIPULATE_ROOT/scripts/mcp_menu.py" ]; then
flake.nix:1129:              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/mcp_menu.py"
flake.nix:1147:          # `pipulate mcp-discover` keep working inside the shell instead of
flake.nix:1194:          # invoke an alias on a human's behalf, and mcp_menu.py's roster names
(nix) pipulate $ 
```

**2: Context**:

```text
# adhoc.txt    _   _   _ to set context____ _   _  ___  ____  _   <F5> Simpson Couch Gag Here (explain anything to the audience you feel needs it explained)
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  Some 80 column thing.
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  
# Ad Hoc CHOP: The Not-Managed-by-Git Safe-for-Client-Data place  

# THE ROLLING PIN BOOK ORE SPINE / FODDER FOR THE BOOK
# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- The "Rolling Pin" that gives the 40K foot book-spine view of book-ore.
GLOSSARY.md                 # <-- I think this glossary goes well with the book-ore spine to do world building.
# scripts/articles/lsa.py     # <-- Useful for refining commands like `posts`, critical to Second Brain concept.

# THE QUIRKY AMIGA-LOVING HUMAN
~/repos/nixos/autognome.py  # <-- Letting the AIs really understand my environment (The Brave Little Tailor punches above Their Weight Class proving the dunning-kruger effect the gate-keeper's (lower-case) lament.)
init.lua                    # <-- Daily driver hot-keys that overlap with aliases in flake.nix

# THE HAND-CRANKED AGENTIC FRAMEWORK
prompt_foo.py               # <-- Prompt Fu compiler, makes the very README for AGENTS-like payload you're reading right now, but it needs to be more like that
foo_files.py                # <-- This is the router, evolving book outline and the things you pin-up to produced the recursive self-improvement loops

# MAIN ACTUATORS, IaC & NEGATIVE SPACE
apply.py                    # <-- How can "Web UI" ChatBots edit your code? With this Aider-inspired Player Piano patch applier.
.gitattributes              # <-- Model: understand that `nbstripout` and `jupytext` are both in play. Just talk the human through .ipynb patches.
.gitignore                  # <-- Creates "negative space" for sub-rep's to share parent environment and "snap" proprietary secret features into place.
flake.nix                   # <-- Solves world's WRITE ONCE RUN ANYWHERE problem like Java never could. Also resolves the bootstrap paradox.
requirements.in             # <-- All known dependencies and (necessary) version pinning. WORA gotcha's exposed.
__init__.py                 # <-- Master versioning
pyproject.toml              # <-- The PyPI Packaging details
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.
 
# CONTEXT PORTABILITY SYSTEM
scripts/foo_cartridge.py    # Needs description
scripts/foo_replay.py       # Needs description
 
# # FREQUENTLY USEFUL TO HAVE IN CONTEXT
release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.

# imports/voice_synthesis.py  # <-- The wand can talk to you
# 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.  ---

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

# server.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
  
# tools/scraper_tools.py
# tools/__init__.py
# tools/dom_tools.py
# tools/llm_optics.py
scripts/walk.py

assets/trails/first_context.yaml
scripts/weblogin.py

# ! ls browser_cache/looking_at

assets/installer/replay.sh
scripts/mother_cat.py

# # `d`, `Shift`+`G`! I have to remember that.
# 
# ! { echo "== auth ruling witness =="; grep -c 'NOT distinct rides at the trail level' foo_files.py | sed 's/^/auth_ruling=/'; grep -c '^# assets/trails/' foo_files.py | sed 's/^/trail_lines=/'; }
# ! { echo "== botify guided captures =="; .venv/bin/python -c 'import glob,json; F=sorted(glob.glob("browser_cache/looking_at/app.botify.com/*/headers.json")); print("captures", len(F)); [print(json.dumps({"provenance": h.get("source_provenance"), "selection": h.get("header_selection"), "title_len": len(h.get("title") or ""), "login_marker": any(t in (h.get("final_url") or "").lower() for t in ("signin", "login", "sso"))})) for f in F for h in [json.load(open(f, encoding="utf-8"))]]'; }
# ! { echo "== non-ascii in url-bearing frontmatter, uncapped =="; .venv/bin/python -c 'import glob,os; P=sorted(glob.glob(os.path.expanduser("~/repos/trimnoir/_posts/*.md"))); print("scanned", len(P)); [print(ascii(os.path.basename(f)), ascii(l)) for f in P for l in open(f,encoding="utf-8").read().split(chr(10)) if l.startswith(("permalink:","canonical_url:")) and any(ord(c) > 127 for c in l)]'; }
# ! { echo "== router burden by region =="; .venv/bin/python -c 'p=open("foo_files.py",encoding="utf-8").read(); i=p.find("# " + "#todo #to-do"); j=p.find("XIX. THE PAINTBOX"); print("total_bytes", len(p)); print("earmark_bytes", (j-i) if 0 < i < j else "MARKER-MISS"); print("paintbox_bytes", (len(p)-j) if j > 0 else "MARKER-MISS")'; }
# foo_files.py
# GLOSSARY.md
# scripts/walk.py
# scripts/mother_cat.py
# scripts/walk_cartridge.py
# scripts/weblogin.py
# tools/scraper_tools.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py
# scripts/connectors/botify.py
# assets/trails/practice.yaml
# assets/trails/public_walk.yaml
# assets/trails/first_context.yaml
# # assets/trails/botify_pageworkers.yaml

# # --- PROBE ECHOES (verbatim from car 1) ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -30
# 
# # --- ACQUISITION: uncomment exactly ONE, chosen by the wc receipt ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 400
# 
# # --- THE JIRA LANE (deliberately leaner than this compile) ---
# scripts/connectors/README.md
# scripts/connectors/jira.py
# scripts/connectors/wallet.py
# init.lua
# flake.nix
# foo_files.py
# prompt_foo.py
# apply.py

# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,re,httpx; b=(os.getenv("JIRA_URL") or re.sub(r"/wiki/?$","",(os.getenv("CONFLUENCE_URL") or os.getenv("CONFLUENCE_BASE_URL") or "").rstrip("/"))).rstrip("/"); r=httpx.get(b+"/_edge/tenant_info",timeout=15); print("tenant_info",r.status_code,r.text[:160]); s=httpx.get(b+"/rest/api/3/serverInfo",timeout=15); print("serverInfo",s.status_code,(s.json().get("deploymentType") if s.status_code==200 else s.text[:80]))'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc

# ~/repos/nixos/autognome.py                 #  <-- More rare to have to include, but the true "top" of the muscle memory stack for day-to-day purposes
# ~/repos/nixos/configuration.nix            #  <-- "Global" IaC context (most of you won't have)
# ~/repos/nixos/blogs.nix
# ~/repos/nixos/packages.nix                 #  <-- Full disclosure on pre-flake IaC available apps.
# ~/repos/nixos/services.nix                 #  <-- Running Linux system services.
# ~/repos/nixos/ai-acceleration.nix          #  <-- Paid a lot for your hardware? We've got you covered.
# ~/repos/nixos/hardware-configuration.nix   #  <-- Automatically generated by Nix. The ultimate in IaC transparency.

# scripts/articles/common.py                   # <-- Self-explanatory
# scripts/articles/confluenceizer.py           # <-- Idempotent Jekyll-to-Confluence corporate wiki

# scripts/connectors/jira.py
# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,httpx; b=os.environ["JIRA_URL"].rstrip("/"); r=httpx.get(b+"/rest/api/3/myself",auth=httpx.BasicAuth(os.environ["JIRA_EMAIL"],os.environ["JIRA_TOKEN"]),headers={"Accept":"application/json"},timeout=15); print("myself_status="+str(r.status_code)); print("seraph="+str(r.headers.get("x-seraph-loginreason"))); print(r.text[:200])'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 30

# /home/mike/repos/trimnoir/_posts/2026-08-24-paste-what-you-have-composable-text-commands.md
# 
# scripts/boot_menu.py  # [1,671 tokens | 6,636 bytes]
# scripts/mcp_menu.py
# assets/installer/mck.sh     # <-- THE LAUNCHER: curl -fsSL pipulate.com/mck.sh | bash
# assets/installer/install.sh   # The magic cookie: curl-distributed, git-free bootstrap

! COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
! .venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
! rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40

scripts/mcp_menu.py
scripts/boot_menu.py
```

**3: Patches**: 

```diff
(nix) pipulate $ ahe
(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
❌ Error: Missing target filename before the SEARCH block.

--- DIAGNOSTIC: Payload context around SEARCH block ---
  The [[[SEARCH]]] block was found but no 'Target: `filename`' line
  immediately preceded it. Here is what WAS there:
     1: '[[[SEARCH]]]'
     2: 'wallet.py — Score, check, and warm every credential in the Pipulate wallet.'
     3: '[[[DIVIDER]]]'
     4: 'wallet.py — Connect your accounts and see which credentials are live.'

  FIX: Add 'Target: `path/to/file`' on the line
  immediately before the [[[SEARCH]]] marker, no blank lines between.
--- END DIAGNOSTIC ---

(nix) pipulate $ vim patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/wallet.py'.
(nix) pipulate $ d
diff --git a/scripts/connectors/wallet.py b/scripts/connectors/wallet.py
index 0bac2fda..8f8134cd 100644
--- a/scripts/connectors/wallet.py
+++ b/scripts/connectors/wallet.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 # scripts/connectors/wallet.py
 """
-wallet.py — Score, check, and warm every credential in the Pipulate wallet.
+wallet.py — Connect your accounts and see which credentials are live.
 
 Golden-path modes, auto-detected from the leading positional argument:
 
(nix) pipulate $ m
📝 Committing: chore: Update wallet.py description
[main 2098ba28] chore: Update wallet.py description
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ vim patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/mcp_menu.py'.
(nix) pipulate $ d
diff --git a/scripts/mcp_menu.py b/scripts/mcp_menu.py
index d9a471b4..1e9f8fbe 100644
--- a/scripts/mcp_menu.py
+++ b/scripts/mcp_menu.py
@@ -150,6 +150,38 @@ def main():
         print()
 
     width = max(len(command) for command, _ in rows)
+
+    # THE 80-COLUMN BUDGET, SHOUTED RATHER THAN SILENTLY TRUNCATED.
+    # Rich gives a padding=(1,2) Panel a body of console_width - 6, so at the
+    # 80 columns a fresh terminal (and every non-tty lane, including the `!`
+    # executor) defaults to, the body is 74. Each row spends the command
+    # column plus a 3-space gutter -- the same derivation
+    # connectors/README.md already documents, recomputed here from the live
+    # width so a longer command word lowers the ceiling for every row at once.
+    # MAINTAINER-INVISIBLE BY CONSTRUCTION: the author's terminal is ~180
+    # columns, so an over-budget row wraps only for strangers. Row one (warm)
+    # sat at 63 against a 61 budget for the entire life of this roster, and no
+    # one who could fix it was ever in a position to see it.
+    # WARN, NEVER TRUNCATE: MAX_DESC's silent cut is the LAST-INCH failure --
+    # a correct sentence destroyed by the transformation nearest the reader,
+    # with no tell. A loud line names its own fix, stays silent when every row
+    # fits, and the rendered panel below is the independent witness that this
+    # check ran at all. The healthy margin is thin (the longest surviving row
+    # clears by two characters), which is why the guard matters more than the
+    # single row it was written to catch.
+    budget = 74 - width - 3
+    overflows = [
+        (command, description)
+        for command, description in rows
+        if len(description) > budget
+    ]
+    for command, description in overflows:
+        print(
+            f"!!  {command} description is {len(description)} chars against a "
+            f"{budget}-char budget -- this row WILL WRAP at 80 columns."
+        )
+    if overflows:
+        print()
     body = "\n".join(
         f"{command.ljust(width)}   {description}"
         for command, description in rows
(nix) pipulate $ m
📝 Committing: chore: Clarify 80-column budget enforcement in mcp_menu.py
[main 7dc37d47] chore: Clarify 80-column budget enforcement in mcp_menu.py
 1 file changed, 32 insertions(+)
(nix) pipulate $ git push
Enumerating objects: 14, done.
Counting objects: 100% (14/14), done.
Delta compression using up to 48 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 1.78 KiB | 1.78 MiB/s, done.
Total 9 (delta 7), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (7/7), completed with 5 local objects.
To github.com:pipulate/pipulate.git
   e1294c47..7dc37d47  main -> main
(nix) pipulate $ 
```

**4: Prompt**: Both patches landed and need no ignition -- mcp_menu.py and wallet.py are read from disk every time the roster renders, so the AFTER receipts in this compile are real readings.

Read the LIVE COMMAND RECEIPTS and rule:

- If the budget one-liner's receipt prints only the "width / budget" line and nothing after it, every row now fits and the overflow is closed. If it still names a row, say which and by how many characters.
- If the rendered panel's receipt shows the warm row on a single line at 80 columns, the visible half is closed too. If the two receipts disagree -- one says fits, the other wraps -- that is a finding about my arithmetic, not about the rows, and it outranks both readings.
- If either receipt is absent from the Manifest, the echo did not land and there is no AFTER; say so instead of ruling from my hand-run.
- None of the above is a live option: if something happened that fits no branch here, name it rather than forcing it into one.

Then the word. I have not decided, and I want your read against the rg receipt before I sweep. Give me:

1. The three-word split you would actually ship for the three jobs `mcp` currently does -- the human roster, the cli.py tool dispatcher, and the real Streamable-HTTP client in scripts/connectors/mcp.py that has no alias because the word is taken.
2. The complete same-car sweep list read off the rg receipt: every string that has to move in one commit, including whether scripts/mcp_menu.py itself gets renamed, and whether the CONNECTOR ALIAS TRANSITION earmark in foo_files.py is discharged by that car or survives it.
3. Whether the boot_menu card should keep listing three words at all, given that pu, the roster, and learn are three different categories of thing.

**5: Deliverables**: Less between intro to this system and it "just working".

Hmmm. So it's suggesting "sources" as a way of listing the sources. I probably
want to change the `learn` alias to something else because it's not semantically
correct right now. `help` and `learn` should all at least step you towards
getting your list of available sources.

The next thought here is that I actually want to phase out the concept of
Pipulate on most booth paths, especially the Figlet in all conditions except
where "1" is chosen after a `nix develop`. Otherwise the so-called *identity* of
this system should be: "Generic nix installed: True" where currently the
Pipulate identity is strongly communicated with Figlet. So this is a "how are we
doing?" turn, plus just beginning to plot out the next steps.

**Opus 5 Max**: Context verified.

## 1. The ruling: both halves closed, and the model of the width is now witnessed

All three echoed lines appear in the Manifest's LIVE COMMAND RECEIPTS, so there is a real AFTER.

**The budget one-liner** printed `width 10 budget 61` and stopped. No row named. **Overflow closed.**

**The rendered panel** shows `warm` on one line at 80 columns. **Visible half closed.**

They agree, and the agreement is stronger than "no row exceeded." Your hand-run BEFORE tap read `63 warm '...'` with the row visibly wrapping; the AFTER reads silence with the row intact. One command, two taps, patch between — a clean straddle in both directions.

The arithmetic checks against the render independently: `warm` is now 57 against a 61 budget, `botify` is 59 (the longest survivor, clearing by exactly 2 — the comment's claim, confirmed), and `10 + 3 + 59 + 2 = 74` is precisely the body width the panel drew. So the *derivation* is validated, not just the outcome. That matters more than the row: the guard now fires correctly the day a command word grows. `sources` (7) is shorter than `confluence` (10), so a roster rename does not move the budget — but adding a row named `connectors` or `credentials` would put you back at 61 with `botify` at 59 and one character of slack.

One non-finding worth naming so nobody hunts it: the git-diff telemetry shows **only** the `mcp_menu.py` commit. The tree was clean, so `git diff HEAD` fell back to `HEAD~1..HEAD` = one commit. The `wallet.py` car is at `HEAD~2..HEAD~1` and is invisible here. That is documented behavior (`diff_label` reads "Most Recent Commit Changes" rather than over-claiming), not a missing patch. But it means **a two-car ride can only ever show its last car** in Telemetry, which is a real limit on the compile as a ride-witness.

---

## 2. The thing that fits no branch: I broke rule 8 twice and you paid for it in vim

```text
❌ Error: Missing target filename before the SEARCH block.
```
…then `vim patch`, then `app` succeeded. **Twice.** Both cars.

That is not in your prompt's branch list and it is the most valuable thing in this turn, because the fault is in the **emitter**, not the operator.

**Cause, mechanically:** my previous turn put `Target: scripts/connectors/wallet.py` *above* the fence and `[[[SEARCH]]]` as the fence's first line. A web chat UI's one-click copy control copies the fence **body and nothing else**. So the Target line was not merely badly placed — it was **structurally unreachable by the path you actually use**. Rule 8 already says "enclose the `Target:` line *and* the block inside a single fence." I violated it and the invariant caught it exactly as designed.

**This is a fourth refusal class, and the constitution names only three.** `apply.py`'s `block_pattern` matched a complete SEARCH/DIVIDER/REPLACE triple; the optional Target group came back empty. So the markers *parsed*, the body was extracted *intact*, and the diagnostic **printed that body back verbatim** before refusing — you saw lines 1–4 on screen.

That makes it the one refusal in the family where **hand-repair is witnessed**: adding a Target line cannot touch a body you just read, and the exact-match interlock still ran on it unmodified. Your two `vim patch` edits were correct. Contrast:

| refusal | markers | body | hand-repair? |
|---|---|---|---|
| no-blocks-found | never parsed | never read | **never** |
| search-block-not-found | parsed | read and rejected | diagnosable |
| AST/language, with lineno | parsed | first error only (a floor) | **never** on whole-file |
| **missing-target** | parsed | **read and printed** | **witnessed** |

Both patches below bank this. The cure is in the emitter, never in your vim.

---

## 3. The word: `sources` / `tools` / `mcp`

`mcp` is not one name to change. It is one name doing three jobs, and the deeper defect is that **its bare form and its argument form point at different universes**: bare `mcp` lists connectors that pull material *in*; `mcp <tool>` dispatches a registry tool. Nothing about the word tells you those are unrelated.

**(a) The roster → `sources`.** Beats the earmark's own `connect` / `pipe` / `warp` for one reason: it names the **output class**, not an action the command doesn't perform. `connect` is a verb, and the roster connects nothing — `warm` does. `sources` also answers yesterday's article literally: *name the source* → so `sources` prints the sources you can name.

Cost, stated: `pu` is definitively not a source. `mcp_menu.py`'s comment already flags that row as a knowing exception; renaming sharpens the exception into a contradiction. Which is convenient, because your #5 wants `pu` off door 2 anyway.

**(b) The dispatcher → `tools`.** This is the one I'd argue hardest for, because it fixes the split-universe problem rather than renaming around it:

```bash
tools() {
  if [ "$#" -eq 0 ]; then
    (cd "$PIPULATE_ROOT" && .venv/bin/python cli.py mcp-discover)
  else
    (cd "$PIPULATE_ROOT" && .venv/bin/python cli.py call "$@")
  fi
}
```

Same shape `mcp()` already has, pointed at a better second door. Bare `tools` prints the Rule-of-7 panel that **already exists and is already curated**; `tools <name>` dispatches. Now bare and argument forms are about the *same thing*, and the symmetry is legible: `sources` lists sources, `tools` lists tools.

A **function**, not an alias, per the THREE-TIER AMENDMENT: it must call another function-or-command in the same shell, and it is only ever typed by a human — no `!` probe needs it.

**(c) `mcp` freed → the real client.** `alias mcp='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/mcp.py"'`, identical in shape to `jira`, `slack`, `botify`. The file name and the word finally agree.

**One trap in (c):** every other connector has a bare-word identity walk. `mcp.py`'s `server` positional is **required**, so bare `mcp` would hit argparse and exit 2 — a *worse* bare-word experience than today. Either `mcp.py` grows a bare mode (print the wallet's known MCP endpoints, or the usage card), or the car accepts "this one needs an argument" and says so. Not a nit; it's the first thing a newcomer will do with the freed word.

---

## 4. The sweep — and what this receipt does *not* size

**Read straight off the receipt (13 lines, `head -40` not hit, so complete for its scope):**

*Behavior — must move or it breaks:*
- `flake.nix:1127` `mcp() {` — the function name
- `flake.nix:1128–1129` — body, incl. the `mcp_menu.py` path
- `scripts/boot_menu.py:187` — the card line

*Labels — must move in the same car (SAME-CAR LABEL RULE):*
- `scripts/mcp_menu.py:3` docstring self-label
- `scripts/mcp_menu.py:6` "type \`mcp\`"
- `scripts/mcp_menu.py:91` FOOTER "Type mcp \<tool_name\>"
- `flake.nix:1113, 1119, 1120, 1125` — the four comments describing the function
- `flake.nix:1194` — `warm`'s comment citing "mcp_menu.py's roster"

*Does **not** move:*
- `flake.nix:1147` `pipulate mcp-discover` — cli.py's real subcommand, unrelated to the shell word.

**Rename the file?** Yes — `sources_menu.py`. A file named for a word it no longer implements is a label lying at the moment of diagnosis. Note the transition is safe by design: a checkout with the old file and a new flake takes the FALL-THROUGH GUARANTEE and behaves as if the function never existed.

**Now the honest part: this receipt scoped three files, and your question was "every string that has to move."** It answered the *shell-surface* question completely and did not size the corpus. Not surveyed: `scripts/connectors/mcp.py` (its own docstring and `mcp GREEN` / `mcp RED` receipt strings), `scripts/connectors/README.md`, `cli.py`, `foo_files.py`'s several MCP rules, `tools/mcp_tools.py`, `imports/mcp_orchestrator.py`, `AI_CONTEXT.md`. Most of those are the *runtime* MCP lane and correctly untouched — but "most" is a guess and this turn cannot upgrade it. Probe 1 below closes that.

**Earmark discharge — and a trap.** The CONNECTOR ALIAS TRANSITION has two clauses: *rename the alias* **and** *free `mcp` for the client*. A car that only renames leaves clause 2 armed — the exact PUBLISH-ROSTER shape, a hazard named with its trigger still live. **Do both in one car and item 3 deletes.**

But it is **item 3 of a five-item earmark**, so deleting the whole block silently drops items 1, 2, 4, 5. And reading that earmark against the source in this payload, **it is already stale in two places:**

- **Item 5 (register the workspace tree as figurate art) is DISCHARGED.** `update_agents_md_in_place`, `update_readme_md_in_place`, and `release.sync_workspace_tree_to_com` all call `figurate("workspace_tree")` and splice it between sentinels. Item 6's deployment surfaces are partly discharged too (README ✓, AGENTS.md ✓, Pipulate.com ✓; `learn` payload and Honeybot not).
- **Item 1's shape changed.** The flake now creates `Notebooks/Playground` and `Notebooks/Shared` with a README, and its THREE BUCKETS comment names canon as `Advanced_Notebooks/Educational_Notebooks/imports` — **not** `Corporate/`. The earmark still names a tier the shipped implementation replaced. PROTECTION-LAG POLARITY, understating what exists. Probe 4 settles whether `Corporate/` exists at all.

---

## 5. The boot card — and why it is the *same story* as the figlet

Your #5 answers Q3 without meaning to. Door 2 is "I do not want the app." Its card's third word is `pu`, which offers the app back. That is a contradiction you just named from a different direction.

But **do not split these into two cars.** The figlet, the panel copy, and the card are one story: *what does this system claim to be on the path where you declined it?* Changing one and not the others is exactly the SAME-CAR LABEL failure — a card describing an identity the banner no longer asserts.

Recommendation for that car:

- **`figlet` + `Version:` move below the `BOOT_CHOICE -eq 10` exit**, into the door-1 branch only. `APP_NAME` / `PROPER_APP_NAME` stay computed early — the browser-poll subshell and the TTS string use `APP_NAME` — only the two display lines move.
- **Door 2 keeps three words, reframed by scope** rather than category: `sources` (reach outside) / `learn` (hand it off) / `pu` (run it here). Three scopes is a coherent axis; "three categories" was the complaint, and scope is the answer to it. `pu` stays because a door-2 user must be able to change their mind, but it goes **last**, not first.
- `.#quiet` is already unaffected — it never reaches `runScript`. Good; the agent lane has never seen a figlet.

**One constraint the move must not break, and one sentence that fails the mechanical test.**

The figlet is currently the only *visible* proof that `runScript` reached step 5 — a weak completion witness for the HALF-EXECUTED HOOK failure. Move it and door 2 loses that. Replace it with a one-line receipt.

But `"Generic nix installed: True"` fails ATTRIBUTED-VOICE twice: **"installed"** names an act this line did not perform, and it is a boolean assertion with no observation behind it. The honest form reports what it *observed*:

```text
(nix) shell ready — v2.44 · .venv/bin/python 3.12 · /home/mike/repos/pipulate
```

Every field there is a reading. And it satisfies THE DISCRIMINATION QUESTION on the *silence* side: in the world where the hook died early, this line does not print at all.

---

## 6. `learn` and `help`

`learn` fails the mechanical test — nobody learns; a payload compiles and a clipboard fills. But the bigger problem is what a newcomer *sees*: the Rich Payload Ledger and the full console summary. At minute zero, "teach me" answers with a token-budget accounting table. That is the machinery showing through at the exact moment the Stick Bug is supposed to be invisible.

**The narrow fix, and its one hard boundary:** a `--quiet` on `prompt_foo.py` gating **step 5 only** — `console_summary` and the Payload Ledger. It must **not** reach step 6. The secrets tripwire's unconditional `🔐 ARMED` line, the render canary count, the PII rewrite lines, and the disclosure receipt all print at step 6, and silencing any of them recreates the SILENT-PASS PROBLEM — an armed gate and a disarmed gate printing identically. Loud stays loud; only the accounting goes quiet.

**`help`:** free-ish, but note it is a **bash builtin**. A shell *function* named `help` does shadow it (functions outrank builtins), so it works — but it is a deliberate shadow, not an empty slot, and worth writing down before someone rediscovers it as a bug. If `help` reprints the door-2 card on demand, the card stops being a one-shot, which is most of what you want.

---

## 1. PROBES

```bash
rg -c --hidden -g '!.git' -w mcp | sort -t: -k2 -rn | head -20
rg -n -e 'alias (help|learn|sources|tools|call|connect)=' -e '^ *(help|learn|sources|tools|call|connect)\(\)' flake.nix
rg -n -e 'figlet' -e 'BOOT_CHOICE' -e 'boot_menu\.py' flake.nix
{ echo "== notebook tiers =="; ls -d Notebooks/*/ 2>/dev/null; echo "== Corporate refs =="; rg -c --hidden -g '!.git' 'Notebooks/Corporate' | head -10; }
```

Probe 1 sizes the sweep the last receipt could not: `-w` makes `\b` word-boundaried, so `mcp_menu` is *excluded* (underscore is a word char) while `mcp-discover` is *included* (hyphen is not) — a known false positive, named rather than filtered, since discriminating them is the point of reading counts per file. `--hidden -g '!.git'` per the DOTFILE-BLIND corollary. Probe 2 asks whether any candidate word already has a definition in our own flake — source-read, so it is lane-independent and does not depend on interactive aliases the `!` executor cannot see. Probe 3 gives the figlet/gate line numbers so the move is planned against a receipt instead of my reading. Probe 4 falsifies my claim that `Corporate/` was replaced by canon.

## 2. NEXT CONTEXT

```text
! rg -c --hidden -g '!.git' -w mcp | sort -t: -k2 -rn | head -20
! rg -n -e 'alias (help|learn|sources|tools|call|connect)=' -e '^ *(help|learn|sources|tools|call|connect)\(\)' flake.nix
! rg -n -e 'figlet' -e 'BOOT_CHOICE' -e 'boot_menu\.py' flake.nix
! { echo "== notebook tiers =="; ls -d Notebooks/*/ 2>/dev/null; echo "== Corporate refs =="; rg -c --hidden -g '!.git' 'Notebooks/Corporate' | head -10; }
```

Every file the sweep car needs is already in the chop. **Consider dropping ballast** — this compile ran 283k tokens and the next one touches the shell surface only. Safe to comment out for one turn: the seven connector bodies (`gmail`, `confluence`, `jira`, `slack`, `botify`, `gsc`, `sheets`, `wallet` ≈ 37k), `autognome.py`, `release.py`, `foo_replay.py`, `foo_cartridge.py`, `walk.py`, `mother_cat.py`, `replay.sh`, `first_context.yaml`, `crawl.py`, `weblogin.py`. **Keep**: `flake.nix`, `boot_menu.py`, `mcp_menu.py`, `cli.py`, `foo_files.py`, `prompt_foo.py`, `apply.py`, `connectors/README.md`, `connectors/mcp.py`.

## 3. PATCHES

One car, one story: **the Target-outside-fence failure of 2026-08-25, both halves — the emitter rule and the operator-side refusal ladder.**

```text
Target: prompt_foo.py
[[[SEARCH]]]
8.  **THE FENCED OUTFLOW INVARIANT:** You MUST enclose the `Target: filename` line and the entire SEARCH/DIVIDER/REPLACE block inside a single ` [triple-backtick]text ` markdown code block. This prevents web chat UIs from stripping leading whitespace, ensuring `apply.py` receives the exact indentation. All opening markdown fences must use a language specifier tag sting such as ` [triple-backtick]text ` so the downstream TTS reader has explicit closures.
[[[DIVIDER]]]
8.  **THE FENCED OUTFLOW INVARIANT:** You MUST enclose the `Target: filename` line and the entire SEARCH/DIVIDER/REPLACE block inside a single ` [triple-backtick]text ` markdown code block. This prevents web chat UIs from stripping leading whitespace, ensuring `apply.py` receives the exact indentation. All opening markdown fences must use a language specifier tag sting such as ` [triple-backtick]text ` so the downstream TTS reader has explicit closures. **THE COPY BUTTON IS THE ACTUATOR, AND IT CANNOT REACH OUTSIDE THE FENCE.** A web chat UI's one-click copy control copies the fence BODY and nothing else, so a `Target:` line placed above the fence is not merely bad style — it is STRUCTURALLY UNCOPYABLE by the path the operator actually uses, and `apply.py` then refuses with "Missing target filename" against a block whose body arrived perfectly intact. Convicted 2026-08-25: a two-car train put both `Target:` lines above their fences, both cars were refused, and the operator hand-repaired both in vim. The `Target:` line goes INSIDE the fence, on the line directly above `[[[SEARCH]]]`.
[[[REPLACE]]]
```

```text
Target: foo_files.py
[[[SEARCH]]]
# by hand in under a minute. OPERATOR-SIDE COROLLARY: when app prints
# no-blocks-found, do NOT edit the patch file -- delete it and ask for a
# re-emit. The emitter is cheap; the unexamined body is not.
[[[DIVIDER]]]
# by hand in under a minute. OPERATOR-SIDE COROLLARY: when app prints
# no-blocks-found, do NOT edit the patch file -- delete it and ask for a
# re-emit. The emitter is cheap; the unexamined body is not.
# FOURTH REFUSAL CLASS (banked 2026-08-25, emitter-convicted): the
# MISSING-TARGET refusal, and it is the one member of this family where a
# hand-repair IS witnessed. apply.py's block_pattern matched a complete
# SEARCH/DIVIDER/REPLACE triple while the OPTIONAL Target group came back
# empty, so the markers PARSED, the body was extracted INTACT, and the
# diagnostic PRINTED that body back verbatim before refusing. Adding a
# Target line therefore cannot touch a body the operator just read on
# screen, and the exact-match interlock still runs on it unmodified --
# unlike no-blocks-found, where nothing ever read the body at all.
# THE CAUSE IS IN THE EMITTER, NOT THE OPERATOR'S VIM: a web chat UI's
# copy button copies the fence BODY ONLY, so a Target line placed ABOVE
# the fence is structurally uncopyable by the path the operator uses.
# Convicted 2026-08-25 when a two-car train put both Target lines outside
# their fences and both cars were refused. Cure: THE FENCED OUTFLOW
# INVARIANT, which now names the copy button as the actuator.
[[[REPLACE]]]
```

**No ignition required.** Both files are read from disk at call time — `prompt_foo.py` executes `_generate_ai_checklist()` on every compile, and `foo_files.py` is imported by `parse_file_list_from_config` on every compile — so the next `ahc` is a real AFTER, not a stale BEFORE wearing the AFTER's label.

Choreography: `patch`, `app`, `d`, `m`, then `blast`.

## 4. PROMPT

```text
Both patches read from disk at compile time, so this compile's receipts are real AFTERs.

Rule from the LIVE COMMAND RECEIPTS, and say which tap each ruling comes from:
- Probe 2: state what the flake already defines among help / learn / sources / tools / call / connect. If it returns zero lines, treat that as evidence about my regex before treating it as evidence about the flake, and say which you concluded.
- Probe 3: give the figlet and BOOT_CHOICE line numbers and say whether the two display lines can move below the door-2 exit without stranding any variable the later code reads. Name the variable if one is stranded.
- Probe 4: does Notebooks/Corporate/ exist on disk, and does anything outside foo_files.py still reference it? This decides whether earmark item 1 is stale in SHAPE or merely unfinished.
- Probe 1: read the per-file counts and split the corpus into (a) the shell-word lane that must move in the rename car and (b) the runtime MCP lane that must not. Name any file you cannot confidently place, rather than placing it.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

I am choosing the word this turn. Assume sources / tools / mcp unless probe 2 shows a collision. Then give me:
1. The rename car as SEARCH/REPLACE blocks against raw source in this context, every Target line INSIDE its fence, covering the behavior lines and the label lines together. Say explicitly whether scripts/mcp_menu.py is renamed in the same car and what the FALL-THROUGH GUARANTEE does during the transition.
2. Whether freeing `mcp` for scripts/connectors/mcp.py requires giving that file a bare-word mode in the same car, or whether "this one needs an argument" is acceptable and where that gets said.
3. The exact lines to delete from and leave in the THREE-TIER WORKSPACE earmark -- item 3 only, plus anything probe 4 or the source shows is already discharged -- as paste-ready text. Do not propose deleting the whole earmark block.

Hold the figlet move and the boot-card rewrite for their own car. They are one story with the panel copy and I do not want them mixed into the rename.
```

## 5. EXTERNAL DELIVERABLES

None this turn.

**MikeLev.in**: Okay, I'm going to take the Claude Opus recommendations.

**1: Probe**:

```bash
(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 $ rg -c --hidden -g '!.git' -w mcp | sort -t: -k2 -rn | head -20
rg -n -e 'alias (help|learn|sources|tools|call|connect)=' -e '^ *(help|learn|sources|tools|call|connect)\(\)' flake.nix
rg -n -e 'figlet' -e 'BOOT_CHOICE' -e 'boot_menu\.py' flake.nix
{ echo "== notebook tiers =="; ls -d Notebooks/*/ 2>/dev/null; echo "== Corporate refs =="; rg -c --hidden -g '!.git' 'Notebooks/Corporate' | head -10; }
apps/240_simon_mcp.py:36
scripts/connectors/mcp.py:26
scripts/mcp_dummy_server.py:22
foo_files.py:22
server.py:11
imports/ai_tool_discovery_simple_parser.py:10
cli.py:10
scripts/connectors/mcp_warm.py:9
AI_CONTEXT.md:9
imports/ascii_displays.py:7
AI_RUNME.py:7
pipulate/core.py:5
flake.nix:5
tools/mcp_tools.py:4
apps/050_documentation.py:4
scripts/mcp_menu.py:2
scripts/continuation_ladder.py:2
scripts/connectors/README.md:2
prompt_foo.py:2
assets/prompts/system_prompt.md:2
1365:          learn() {
471:          figlet                       # For creating ASCII art welcome messages
620:          figlet "$PROPER_APP_NAME"
681:          # boot_menu.py speaks ONLY through its exit code -- 0 start the
685:          # Textual boot_menu.py can replace the stdlib/Rich one and this
688:          # FALL-THROUGH GUARANTEE: if scripts/boot_menu.py is absent -- an
692:          BOOT_CHOICE=0
693:          if [ -f scripts/boot_menu.py ]; then
694:            python scripts/boot_menu.py
695:            BOOT_CHOICE=$?
697:          if [ "$BOOT_CHOICE" -eq 10 ]; then
1367:              "You are Yen Sid-ton, the onboarding wizard for Pipulate. A newcomer wants to install Pipulate for the first time. Your FIRST reply must be short and do four things in order: (1) confirm in one line that you hold the full install map (installer, flake, both Pipulate.com pages); (2) show the one-line install command immediately, since it is identical on every OS; (3) ask exactly one question, which OS they are on, noting it changes only the caveats, never the command; (4) add one line noting the command assumes Nix is already installed, and that a nix command not found response means install Nix first and reopen the terminal. From then on: one step per turn, one question maximum per turn, and every step ends with a visible success checkpoint describing what they should literally see (the figlet banner, the JupyterLab URL, the spoken voice greeting) plus the single most likely failure symptom at that step and its fix. Deliver the macOS --impure exception and the reopen-your-terminal-after-installing-Nix requirement at the moment each can bite, never as an upfront lecture. Offer the magic cookie internals (ZIP + ROT13 key, then git transformation and auto-updates inside nix develop) as an optional aside when relevant or when asked, not as mandatory explanation. When both the server and JupyterLab are confirmed running, declare the install banked and teach the re-entry incantation: cd into the install folder, then nix develop. High signal, low noise. Ask them what they see; never assume." \
== notebook tiers ==
Notebooks/Advanced_Notebooks/  Notebooks/Deliverables/           Notebooks/__pycache__/
Notebooks/browser_cache/       Notebooks/Educational_Notebooks/  Notebooks/Shared/
Notebooks/Client_Work/         Notebooks/imports/
Notebooks/data/                Notebooks/Playground/
== Corporate refs ==
foo_files.py:1
(nix) pipulate $ 
```

**2: Context**:

```text
# adhoc.txt    _   _   _ to set context____ _   _  ___  ____  _   <F5> Simpson Couch Gag Here (explain anything to the audience you feel needs it explained)
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  Some 80 column thing.
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  
# Ad Hoc CHOP: The Not-Managed-by-Git Safe-for-Client-Data place  

# THE ROLLING PIN BOOK ORE SPINE / FODDER FOR THE BOOK
# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- The "Rolling Pin" that gives the 40K foot book-spine view of book-ore.
GLOSSARY.md                 # <-- I think this glossary goes well with the book-ore spine to do world building.
# scripts/articles/lsa.py     # <-- Useful for refining commands like `posts`, critical to Second Brain concept.

# THE QUIRKY AMIGA-LOVING HUMAN
~/repos/nixos/autognome.py  # <-- Letting the AIs really understand my environment (The Brave Little Tailor punches above Their Weight Class proving the dunning-kruger effect the gate-keeper's (lower-case) lament.)
init.lua                    # <-- Daily driver hot-keys that overlap with aliases in flake.nix

# THE HAND-CRANKED AGENTIC FRAMEWORK
prompt_foo.py               # <-- Prompt Fu compiler, makes the very README for AGENTS-like payload you're reading right now, but it needs to be more like that
foo_files.py                # <-- This is the router, evolving book outline and the things you pin-up to produced the recursive self-improvement loops

# MAIN ACTUATORS, IaC & NEGATIVE SPACE
apply.py                    # <-- How can "Web UI" ChatBots edit your code? With this Aider-inspired Player Piano patch applier.
.gitattributes              # <-- Model: understand that `nbstripout` and `jupytext` are both in play. Just talk the human through .ipynb patches.
.gitignore                  # <-- Creates "negative space" for sub-rep's to share parent environment and "snap" proprietary secret features into place.
flake.nix                   # <-- Solves world's WRITE ONCE RUN ANYWHERE problem like Java never could. Also resolves the bootstrap paradox.
requirements.in             # <-- All known dependencies and (necessary) version pinning. WORA gotcha's exposed.
__init__.py                 # <-- Master versioning
pyproject.toml              # <-- The PyPI Packaging details
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.
 
# CONTEXT PORTABILITY SYSTEM
scripts/foo_cartridge.py    # Needs description
scripts/foo_replay.py       # Needs description
 
# # FREQUENTLY USEFUL TO HAVE IN CONTEXT
release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.

# imports/voice_synthesis.py  # <-- The wand can talk to you
# 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.  ---

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

# server.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
  
# tools/scraper_tools.py
# tools/__init__.py
# tools/dom_tools.py
# tools/llm_optics.py
scripts/walk.py

assets/trails/first_context.yaml
scripts/weblogin.py

# ! ls browser_cache/looking_at

assets/installer/replay.sh
scripts/mother_cat.py

# # `d`, `Shift`+`G`! I have to remember that.
# 
# ! { echo "== auth ruling witness =="; grep -c 'NOT distinct rides at the trail level' foo_files.py | sed 's/^/auth_ruling=/'; grep -c '^# assets/trails/' foo_files.py | sed 's/^/trail_lines=/'; }
# ! { echo "== botify guided captures =="; .venv/bin/python -c 'import glob,json; F=sorted(glob.glob("browser_cache/looking_at/app.botify.com/*/headers.json")); print("captures", len(F)); [print(json.dumps({"provenance": h.get("source_provenance"), "selection": h.get("header_selection"), "title_len": len(h.get("title") or ""), "login_marker": any(t in (h.get("final_url") or "").lower() for t in ("signin", "login", "sso"))})) for f in F for h in [json.load(open(f, encoding="utf-8"))]]'; }
# ! { echo "== non-ascii in url-bearing frontmatter, uncapped =="; .venv/bin/python -c 'import glob,os; P=sorted(glob.glob(os.path.expanduser("~/repos/trimnoir/_posts/*.md"))); print("scanned", len(P)); [print(ascii(os.path.basename(f)), ascii(l)) for f in P for l in open(f,encoding="utf-8").read().split(chr(10)) if l.startswith(("permalink:","canonical_url:")) and any(ord(c) > 127 for c in l)]'; }
# ! { echo "== router burden by region =="; .venv/bin/python -c 'p=open("foo_files.py",encoding="utf-8").read(); i=p.find("# " + "#todo #to-do"); j=p.find("XIX. THE PAINTBOX"); print("total_bytes", len(p)); print("earmark_bytes", (j-i) if 0 < i < j else "MARKER-MISS"); print("paintbox_bytes", (len(p)-j) if j > 0 else "MARKER-MISS")'; }
# foo_files.py
# GLOSSARY.md
# scripts/walk.py
# scripts/mother_cat.py
# scripts/walk_cartridge.py
# scripts/weblogin.py
# tools/scraper_tools.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py
# scripts/connectors/botify.py
# assets/trails/practice.yaml
# assets/trails/public_walk.yaml
# assets/trails/first_context.yaml
# # assets/trails/botify_pageworkers.yaml

# # --- PROBE ECHOES (verbatim from car 1) ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -30
# 
# # --- ACQUISITION: uncomment exactly ONE, chosen by the wc receipt ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 400
# 
# # --- THE JIRA LANE (deliberately leaner than this compile) ---
# scripts/connectors/README.md
# scripts/connectors/jira.py
# scripts/connectors/wallet.py
# init.lua
# flake.nix
# foo_files.py
# prompt_foo.py
# apply.py

# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,re,httpx; b=(os.getenv("JIRA_URL") or re.sub(r"/wiki/?$","",(os.getenv("CONFLUENCE_URL") or os.getenv("CONFLUENCE_BASE_URL") or "").rstrip("/"))).rstrip("/"); r=httpx.get(b+"/_edge/tenant_info",timeout=15); print("tenant_info",r.status_code,r.text[:160]); s=httpx.get(b+"/rest/api/3/serverInfo",timeout=15); print("serverInfo",s.status_code,(s.json().get("deploymentType") if s.status_code==200 else s.text[:80]))'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc

# ~/repos/nixos/autognome.py                 #  <-- More rare to have to include, but the true "top" of the muscle memory stack for day-to-day purposes
# ~/repos/nixos/configuration.nix            #  <-- "Global" IaC context (most of you won't have)
# ~/repos/nixos/blogs.nix
# ~/repos/nixos/packages.nix                 #  <-- Full disclosure on pre-flake IaC available apps.
# ~/repos/nixos/services.nix                 #  <-- Running Linux system services.
# ~/repos/nixos/ai-acceleration.nix          #  <-- Paid a lot for your hardware? We've got you covered.
# ~/repos/nixos/hardware-configuration.nix   #  <-- Automatically generated by Nix. The ultimate in IaC transparency.

# scripts/articles/common.py                   # <-- Self-explanatory
# scripts/articles/confluenceizer.py           # <-- Idempotent Jekyll-to-Confluence corporate wiki

# scripts/connectors/jira.py
# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,httpx; b=os.environ["JIRA_URL"].rstrip("/"); r=httpx.get(b+"/rest/api/3/myself",auth=httpx.BasicAuth(os.environ["JIRA_EMAIL"],os.environ["JIRA_TOKEN"]),headers={"Accept":"application/json"},timeout=15); print("myself_status="+str(r.status_code)); print("seraph="+str(r.headers.get("x-seraph-loginreason"))); print(r.text[:200])'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 30

# /home/mike/repos/trimnoir/_posts/2026-08-24-paste-what-you-have-composable-text-commands.md
# 
# scripts/boot_menu.py  # [1,671 tokens | 6,636 bytes]
# scripts/mcp_menu.py
# assets/installer/mck.sh     # <-- THE LAUNCHER: curl -fsSL pipulate.com/mck.sh | bash
# assets/installer/install.sh   # The magic cookie: curl-distributed, git-free bootstrap

! COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
! .venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
! rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40

# scripts/mcp_menu.py
# scripts/boot_menu.py

# scripts/connectors/mcp.py
# scripts/connectors/README.md
# cli.py
# foo_files.py
# tools/mcp_tools.py
# imports/mcp_orchestrator.py
# AI_CONTEXT.md

! rg -c --hidden -g '!.git' -w mcp | sort -t: -k2 -rn | head -20
! rg -n -e 'alias (help|learn|sources|tools|call|connect)=' -e '^ *(help|learn|sources|tools|call|connect)\(\)' flake.nix
! rg -n -e 'figlet' -e 'BOOT_CHOICE' -e 'boot_menu\.py' flake.nix
! { echo "== notebook tiers =="; ls -d Notebooks/*/ 2>/dev/null; echo "== Corporate refs =="; rg -c --hidden -g '!.git' 'Notebooks/Corporate' | head -10; }
```

**3: Patches**: 

```diff
(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 'prompt_foo.py'.
(nix) pipulate $ d
diff --git a/prompt_foo.py b/prompt_foo.py
index c5834748..31c10e63 100644
--- a/prompt_foo.py
+++ b/prompt_foo.py
@@ -1475,7 +1475,7 @@ Before addressing the user's prompt, perform the following verification steps:
     2. giving exact cell-replacement instructions,
     3. recommending a Jupyter/manual edit followed by the project’s notebook sync hook.
 7.  **INDENTATION IS SACRED:** Every SEARCH block must be copy-pasted character-for-character from the raw source shown in this prompt. Count the leading spaces on the first line of the target block. Your SEARCH block must start with exactly that many spaces — not more, not fewer. The REPLACE block must preserve the same base indentation as the SEARCH block, with any nested code indented relatively from that base. Do not align code for conversational readability. Do not add protective padding. Do not normalize tabs or spaces.
-8.  **THE FENCED OUTFLOW INVARIANT:** You MUST enclose the `Target: filename` line and the entire SEARCH/DIVIDER/REPLACE block inside a single ` [triple-backtick]text ` markdown code block. This prevents web chat UIs from stripping leading whitespace, ensuring `apply.py` receives the exact indentation. All opening markdown fences must use a language specifier tag sting such as ` [triple-backtick]text ` so the downstream TTS reader has explicit closures.
+8.  **THE FENCED OUTFLOW INVARIANT:** You MUST enclose the `Target: filename` line and the entire SEARCH/DIVIDER/REPLACE block inside a single ` [triple-backtick]text ` markdown code block. This prevents web chat UIs from stripping leading whitespace, ensuring `apply.py` receives the exact indentation. All opening markdown fences must use a language specifier tag sting such as ` [triple-backtick]text ` so the downstream TTS reader has explicit closures. **THE COPY BUTTON IS THE ACTUATOR, AND IT CANNOT REACH OUTSIDE THE FENCE.** A web chat UI's one-click copy control copies the fence BODY and nothing else, so a `Target:` line placed above the fence is not merely bad style — it is STRUCTURALLY UNCOPYABLE by the path the operator actually uses, and `apply.py` then refuses with "Missing target filename" against a block whose body arrived perfectly intact. Convicted 2026-08-25: a two-car train put both `Target:` lines above their fences, both cars were refused, and the operator hand-repaired both in vim. The `Target:` line goes INSIDE the fence, on the line directly above `[[[SEARCH]]]`.
 9.  **THE TARGET ADJACENCY RULE:** Every `[[[SEARCH]]]` marker must be immediately preceded by `Target: filename` on the line directly above it — no blank lines, no fences, no prose between the Target line and the marker. The filename in the Target line is what `apply.py` uses to find the file; omitting it or separating it with blank lines causes a fatal "Missing target filename" error. Example: `Target: scripts/articles/lsa.py` or `Target: /home/mike/repos/pipulate/scripts/articles/lsa.py`. Both relative and absolute paths work.
 10.  **THE WHOLE-FILE WRITE ESCAPE HATCH:** For a genuine top-to-bottom rewrite of a single file (not a surgical edit), you MAY skip the SEARCH block entirely. Emit a `Target: filename` line, then on the next line a `[[[WRITE_FILE]]]` marker, then the complete new file body, then a `[[[END_WRITE_FILE]]]` marker — all wrapped in a single fenced text block exactly as the SEARCH/REPLACE protocol requires. `apply.py` writes the body verbatim, overwriting the file if it exists or creating it (and any missing parent directories) if it does not, runs the same Python AST safety check before saving, and normalizes a single trailing newline. Use this ONLY when you are replacing essentially the entire file; for every smaller change the SEARCH/REPLACE protocol with its exact-match interlock remains mandatory, because that exact match is what proves the edit is landing in the right place.
 11.  **THE ACTIONABLE RESPONSE CONTRACT (TURN SHAPE / THE PATCH TRAIN):** Every substantive answer must END with a numbered next-actions plan in this exact order: (1) PROBES — ONE paste-ready fenced block of bare, read-only commands; all annotation (what each proves or falsifies, what it gates) lives in prose outside the block, never inline. Probes are read-only: patch application is never a probe. (2) NEXT CONTEXT — the exact adhoc.txt lines and file paths for the next compile; probe echoes are copy-symmetric with (1): identical commands, each adding only the leading "! ". (3) PATCHES — SEARCH/REPLACE blocks ONLY against raw source actually present in this context (mutating shell actuators such as sed belong here, ridden as their own train car — never in PROBES); if no repo patch is needed, state "No repo patches required" explicitly rather than inventing one. (4) PROMPT — the CABOOSE COPY: the prompt.md text for the next turn, in its own fenced block, riding last so it sits under the operator's cursor when the train stops. (5) EXTERNAL DELIVERABLES — artifacts living outside this repo (PageWorkers JavaScript, CMS settings, dashboards), clearly labeled as manual-paste and never wrapped in patch markers. Actuation choreography is the train itself: patch, app, d, m per car; blast (or git push) as the caboose. Analysis that does not close with this plan is an incomplete answer.
(nix) pipulate $ m
📝 Committing: chore: Enhance prompt_foo.py with detailed outflow invariance instructions
[main ce2c232c] chore: Enhance prompt_foo.py with detailed outflow invariance instructions
 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 b245942a..d9e80c0c 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -522,6 +522,21 @@ AI_PHOOEY_CHOP = r"""#
 # by hand in under a minute. OPERATOR-SIDE COROLLARY: when app prints
 # no-blocks-found, do NOT edit the patch file -- delete it and ask for a
 # re-emit. The emitter is cheap; the unexamined body is not.
+# FOURTH REFUSAL CLASS (banked 2026-08-25, emitter-convicted): the
+# MISSING-TARGET refusal, and it is the one member of this family where a
+# hand-repair IS witnessed. apply.py's block_pattern matched a complete
+# SEARCH/DIVIDER/REPLACE triple while the OPTIONAL Target group came back
+# empty, so the markers PARSED, the body was extracted INTACT, and the
+# diagnostic PRINTED that body back verbatim before refusing. Adding a
+# Target line therefore cannot touch a body the operator just read on
+# screen, and the exact-match interlock still runs on it unmodified --
+# unlike no-blocks-found, where nothing ever read the body at all.
+# THE CAUSE IS IN THE EMITTER, NOT THE OPERATOR'S VIM: a web chat UI's
+# copy button copies the fence BODY ONLY, so a Target line placed ABOVE
+# the fence is structurally uncopyable by the path the operator uses.
+# Convicted 2026-08-25 when a two-car train put both Target lines outside
+# their fences and both cars were refused. Cure: THE FENCED OUTFLOW
+# INVARIANT, which now names the copy button as the actuator.
 
 # THE CARRIED-DELIVERABLE RULE (banked 2026-07-29, operator-convicted): a
 # Car-5 external deliverable is CARRIED, NOT CITED. Car 5's actuator is the
(nix) pipulate $ m
📝 Committing: chore: Refactor: Clarify missing-target refusal explanation in foo_files.py
[main 022e8d5d] chore: Refactor: Clarify missing-target refusal explanation in foo_files.py
 1 file changed, 15 insertions(+)
(nix) pipulate $ git push
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 48 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 1.76 KiB | 360.00 KiB/s, done.
Total 6 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (4/4), completed with 3 local objects.
To github.com:pipulate/pipulate.git
   7dc37d47..022e8d5d  main -> main
(nix) pipulate $
```

**4: Prompt**: 

Both patches read from disk at compile time, so this compile's receipts are real AFTERs.

Rule from the LIVE COMMAND RECEIPTS, and say which tap each ruling comes from:
- Probe 2: state what the flake already defines among help / learn / sources / tools / call / connect. If it returns zero lines, treat that as evidence about my regex before treating it as evidence about the flake, and say which you concluded.
- Probe 3: give the figlet and BOOT_CHOICE line numbers and say whether the two display lines can move below the door-2 exit without stranding any variable the later code reads. Name the variable if one is stranded.
- Probe 4: does Notebooks/Corporate/ exist on disk, and does anything outside foo_files.py still reference it? This decides whether earmark item 1 is stale in SHAPE or merely unfinished.
- Probe 1: read the per-file counts and split the corpus into (a) the shell-word lane that must move in the rename car and (b) the runtime MCP lane that must not. Name any file you cannot confidently place, rather than placing it.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

I am choosing the word this turn. Assume sources / tools / mcp unless probe 2 shows a collision. Then give me:
1. The rename car as SEARCH/REPLACE blocks against raw source in this context, every Target line INSIDE its fence, covering the behavior lines and the label lines together. Say explicitly whether scripts/mcp_menu.py is renamed in the same car and what the FALL-THROUGH GUARANTEE does during the transition.
2. Whether freeing `mcp` for scripts/connectors/mcp.py requires giving that file a bare-word mode in the same car, or whether "this one needs an argument" is acceptable and where that gets said.
3. The exact lines to delete from and leave in the THREE-TIER WORKSPACE earmark -- item 3 only, plus anything probe 4 or the source shows is already discharged -- as paste-ready text. Do not propose deleting the whole earmark block.

Hold the figlet move and the boot-card rewrite for their own car. They are one story with the panel copy and I do not want them mixed into the rename.

**5: Deliverables**: Closer. How did we do? And take the next step towards what
we're discussing here. There's a lot of little nuanced pieces. Don't try to do
too much at once. Take discrete chisel-strike steps with each described such as
sorting out the `mcp` command. I think we change it to `sources` and change a
different Python script to fill that available space with its own default
behavior. That would be plenty for a single step. Even a portion of that is
enough. Oh and "Generic nix installed: True" can be "Generic nix present: True"
to get the idea across.

**Opus 5 Max**: Context verified.

## How we did: all four receipts landed, and one of them convicted my own probe

**Probe 2 — no collision.** The flake defines exactly one of the six candidate words: `1365: learn() {`. The regex is self-validated by that hit (it caught a function with leading spaces, which is the shape it was written for), so the silence about `sources`, `tools`, `call`, and `connect` is evidence about the **flake**, not about my regex. One caveat that is evidence about the regex: it only reads `flake.nix`, so `help` reads free here and is **not** — it is a bash builtin, and a function named `help` would be a deliberate shadow rather than an empty slot. Also unchecked by it: `writeShellScriptBin` names. I read those from source — `posts`, `postsc`, `rgx`, `rgxc`, `ai-commit` — no collision.

**Probe 3 — figlet is movable, nothing is stranded, and there is a label the sweep would have missed.** `471` is the package, `620` is the render, `692–697` is the gate, `697` is the door-2 exit. `PROPER_APP_NAME` has exactly one consumer (line 620), so moving the two display lines below the exit strands nothing; `APP_NAME` stays where it is because the browser-poll subshell reads it. **But line 1367 is the catch:** the `learn` prompt instructs Yen Sid-ton to tell a newcomer that "the figlet banner" is a visible success checkpoint. Move the banner to door 1 only and that instruction becomes false for every door-2 arrival. That line moves in the figlet car, and I would not have known to look for it without this receipt.

**Probe 4 — item 1 is stale in SHAPE, and my probe undercounted.** `Notebooks/Corporate/` does not exist; the tiers on disk are `Advanced_Notebooks / Educational_Notebooks / imports` (canon) + `Playground / Client_Work / Deliverables` (personal) + `Shared`. The only reference anywhere is `foo_files.py:1`. **The pattern was too narrow:** `Notebooks/Corporate` matched item 4's `Notebooks/Corporate/apps/` and was structurally blind to item 1's bare `` `Corporate/` ``. Same disease as the DOTFILE-BLIND / UNANCHORED family — a question only one answer could survive. The ruling holds anyway (nothing outside the earmark references it), but the count is a floor, not a census.

**Probe 1 — the cap was hit exactly, so the list is truncated.** Twenty lines returned against `head -20`, and every count-1 file is invisible. Proof it matters: `scripts/boot_menu.py` carries a bare `mcp` and is **not in the receipt**. I know about it only from the previous compile's `rg -n` and from raw source. Per THE CAP THAT HID THE ANSWER, treat this as a floor.

The split, with `flake.nix:5` independently corroborating the earlier `rg -n` line-by-line:

**(a) shell-word lane, moves this car:** `flake.nix` (4 of 5 — line 1147's `pipulate mcp-discover` is cli.py's real subcommand and stays), `scripts/mcp_menu.py` (2, plus its self-label), `scripts/boot_menu.py` (below the cut), and **`scripts/connectors/README.md`** — I read both its hits from the source in this payload and they are both the phrase *"the `mcp` roster"*, pure labels of the thing that is moving. That file was my "cannot place" last turn; it is placed now, and it is placed in (a).

**(b) runtime lane, does not move:** `apps/240_simon_mcp.py`, `scripts/connectors/mcp.py`, `scripts/mcp_dummy_server.py`, `server.py`, `imports/ai_tool_discovery_simple_parser.py`, `cli.py`, `scripts/connectors/mcp_warm.py`, `imports/ascii_displays.py`, `AI_RUNME.py`, `pipulate/core.py`, `tools/mcp_tools.py`, `apps/050_documentation.py`, `assets/prompts/system_prompt.md`.

**(c) cannot place, named rather than placed:** `foo_files.py` (22 — mixed: the earmark is shell-word, the MCP RECEIPT RULE is runtime; needs reading, not sweeping) and `AI_CONTEXT.md` (9 — generated by `generate_ai_context.py` and regenerated on every release, so it is downstream of whatever it names).

**Nothing happened that fits no branch.** The Target lines landed inside their fences this time and both cars applied first try.

---

## The step: one word split three ways

`sources` for the roster, `tools` for the registry dispatcher, `mcp` freed **and claimed in the same car**. The claim rides along rather than waiting because an alias pointed at `mcp.py`'s required `server` positional would answer the freed word with argparse exit 2 — a worse first keypress than the roster it replaced. Freeing without claiming leaves a hole; claiming without a bare mode leaves a footgun. Both together is one story.

`sources` beats the earmark's own `connect` / `pipe` / `warp` because it names the **output class** rather than an action the command does not perform — the roster connects nothing, `warm` does. And splitting `tools` off is the part that actually fixes something rather than renaming around it: today bare `mcp` and `mcp <tool>` are about different universes with no tell.

**Deliberately not in this car, and why:** the figlet move, the boot-card reframe, and `pu`'s place in the roster — you held those, and probe 3 just added line 1367 to that car's manifest. Also out: adding `mcp` as a *row* in the `sources` roster. Its docstring line is 62 characters against the 61-char budget, so it would trip the guard we just installed — the right fix is a shorter first line, which is an editorial call, not a rename.

`Generic nix present: True` is better than `installed` — "installed" names an act that line did not perform. I would go one step further in that car and report the observation instead of a boolean, e.g. `(nix) shell ready — v2.44 · .venv/bin/python 3.12 · <root>`, because every field there is a reading and it prints nothing at all in the world where the hook died early.

---

## 1. PROBES

```bash
rg -n -e '^ *(sources|tools|mcp)\(\)' -e '^ *alias mcp=' flake.nix
ls scripts/mcp_menu.py scripts/sources_menu.py 2>&1
rg -c -w mcp scripts/connectors/README.md scripts/boot_menu.py; echo "stale_labels_exit=$?"
COLUMNS=80 .venv/bin/python scripts/sources_menu.py
.venv/bin/python scripts/connectors/mcp.py; echo "bare_exit=$?"
```

Probe 1 flips 1 line → 3 and witnesses the **patch**, not the ignition; it reads source, so it is lane-independent. Probe 2 is the two-line witness for the `git mv`. Probe 3 should go from two count lines to silence-plus-`exit=1` — a meaningful-silence receipt, which the `!` executor now lands rather than dropping. Probe 4 proves the mv, the label edits, and that the overflow guard still reads clean in one bounded render; it is deliberately uncapped because the overflow warnings print *above* the panel and any `tail` would hide exactly what it is watching for. Probe 5 flips argparse exit 2 → identity card exit 0.

**Ignition is not witnessed by any of these.** `sources`, `tools`, and `alias mcp` live in the shellHook, which is read once at entry, so the only witness is your own hands after re-entry — noted rather than faked with a `type` probe that would print not-found in the compile lane whether or not the patch landed.

## 2. NEXT CONTEXT

```text
! rg -n -e '^ *(sources|tools|mcp)\(\)' -e '^ *alias mcp=' flake.nix
! ls scripts/mcp_menu.py scripts/sources_menu.py 2>&1
! rg -c -w mcp scripts/connectors/README.md scripts/boot_menu.py; echo "stale_labels_exit=$?"
! COLUMNS=80 .venv/bin/python scripts/sources_menu.py
! .venv/bin/python scripts/connectors/mcp.py; echo "bare_exit=$?"
scripts/sources_menu.py
scripts/boot_menu.py
scripts/connectors/mcp.py
scripts/connectors/README.md
```

**Drop ballast — this compile ran 306k tokens and the next car is the boot-card/figlet story, which touches four files.** Safe to comment out for one turn: the seven connector bodies (`gmail`, `confluence`, `jira`, `slack`, `botify`, `gsc`, `sheets`, `wallet` ≈ 37k), `autognome.py`, `release.py`, `foo_replay.py`, `foo_cartridge.py`, `walk.py`, `mother_cat.py`, `replay.sh`, `first_context.yaml`, `crawl.py`, `weblogin.py`, `GLOSSARY.md`. **Keep**: `flake.nix`, `boot_menu.py`, `sources_menu.py`, `connectors/mcp.py`, `connectors/README.md`, `foo_files.py`, `prompt_foo.py`, `apply.py`, `cli.py`, `init.lua`.

## 3. PATCHES

**Car A — the shell actuator. Run this FIRST, before any patch**, because the fences below Target the file at its new path.

```bash
git mv scripts/mcp_menu.py scripts/sources_menu.py
```

**Car B — the word, split three ways.** One commit story across five files. Apply it as one fence, then `d`, then `m` once.

```text
Target: flake.nix
[[[SEARCH]]]
          # THE SECOND DOOR: bare `mcp` is the roster; `mcp <tool> [args]` is
          # unchanged and still routes to cli.py's tool-call actuator. The
          # word is not technically accurate for the connector rows -- it is
          # the word people already reach for, and reaching for the right
          # word beats being right about the wrong one.
          #
          # FALL-THROUGH GUARANTEE: if scripts/mcp_menu.py has not landed,
          # bare `mcp` behaves EXACTLY as it did before this function existed
          # -- cli.py's own argparse error. A shell must never depend on a
          # file that might not be there.
          #
          # Also fixes a latent white-label bug: the old alias hardcoded
          # ~/repos/pipulate, so `mcp` cd'd into the wrong (or missing)
          # directory for anyone whose install folder is named otherwise.
          mcp() {
            if [ "$#" -eq 0 ] && [ -f "$PIPULATE_ROOT/scripts/mcp_menu.py" ]; then
              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/mcp_menu.py"
            else
              (cd "$PIPULATE_ROOT" && .venv/bin/python cli.py call "$@")
            fi
          }
[[[DIVIDER]]]
          # THE SECOND DOOR, SPLIT IN TWO (2026-08-25). One word was doing two
          # 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
          # 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:
          #
          #   sources        the sources you can name (the roster)
          #   tools          the registry tools you can call
          #   tools <name>   call one
          #   mcp <server>   the real Streamable-HTTP client (aliased below)
          #
          # Discharges the CONNECTOR ALIAS TRANSITION earmark, whose text asked
          # only that the roster be renamed so `mcp` came free. `sources` beats
          # that earmark's own `connect` / `pipe` / `warp` for one reason: it
          # names the OUTPUT CLASS rather than an action the command does not
          # perform. The roster connects nothing; `warm` does.
          #
          # FALL-THROUGH GUARANTEE, and it now REFUSES instead of substituting:
          # if the roster file has not landed, say so in one line. The old
          # spelling fell through to `cli.py call` with no arguments, which
          # answered a DIFFERENT QUESTION with an argparse error. A shell must
          # never depend on a file that might not be there, and it must never
          # quietly answer something else when that file is missing.
          #
          # FUNCTIONS, NOT ALIASES (THE THREE-TIER AMENDMENT): `tools` needs a
          # branch, and both are typed by a human and never echoed as a `!`
          # probe, so neither needs to be a packaged derivation.
          sources() {
            if [ -f "$PIPULATE_ROOT/scripts/sources_menu.py" ]; then
              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/sources_menu.py"
            else
              echo "sources: scripts/sources_menu.py has not landed in this checkout."
            fi
          }
          tools() {
            if [ "$#" -eq 0 ]; then
              (cd "$PIPULATE_ROOT" && .venv/bin/python cli.py mcp-discover)
            else
              (cd "$PIPULATE_ROOT" && .venv/bin/python cli.py call "$@")
            fi
          }
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
          alias jira='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py"'
          alias slack='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/slack.py"'
[[[DIVIDER]]]
          alias jira='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py"'
          alias slack='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/slack.py"'
          # `mcp` NOW MEANS THE CLIENT, which is what the file has always been
          # named. Freed 2026-08-25 when the roster became `sources`, and
          # claimed in the SAME car so the word is never a hole. An ALIAS, not
          # 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"'
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
          # invoke an alias on a human's behalf, and mcp_menu.py's roster names
          # this word to a reader who may reasonably expect it to be reachable.
[[[DIVIDER]]]
          # invoke an alias on a human's behalf, and sources_menu.py's roster
          # names this word to a reader who may reasonably expect it to be
          # reachable.
[[[REPLACE]]]
Target: scripts/boot_menu.py
[[[SEARCH]]]
        print("Three words get you everywhere:")
        print("  learn   hand this whole workshop to an AI in a web chat")
        print("  mcp     see what reaches outside this machine")
        print(f"  pu      start {name} (long form: pipulate)")
[[[DIVIDER]]]
        print("Three words get you everywhere:")
        print("  learn     hand this whole workshop to an AI in a web chat")
        print("  sources   see what reaches outside this machine")
        print(f"  pu        start {name} (long form: pipulate)")
[[[REPLACE]]]
Target: scripts/sources_menu.py
[[[SEARCH]]]
mcp_menu.py — what door 2 opens onto.
[[[DIVIDER]]]
sources_menu.py — what door 2 opens onto.
[[[REPLACE]]]
Target: scripts/sources_menu.py
[[[SEARCH]]]
type `mcp`. This is the roster they get: the commands that reach OUTSIDE
this machine, each row's description GENERATED from the target script's own
[[[DIVIDER]]]
type `sources`. This is the roster they get: the commands that reach OUTSIDE
this machine, each row's description GENERATED from the target script's own
[[[REPLACE]]]
Target: scripts/sources_menu.py
[[[SEARCH]]]
    "Type  mcp <tool_name>  to call a registered MCP tool directly.",
[[[DIVIDER]]]
    "Type  tools  to list registry tools, or  tools <name>  to call one.",
[[[REPLACE]]]
Target: scripts/connectors/README.md
[[[SEARCH]]]
8. THE FIRST DOCSTRING LINE IS A LIVE DISPLAY, not prose. `scripts/mcp_menu.py`
   reads it with `ast.get_docstring` (never an import) and prints it verbatim
   beside the command word in the `mcp` roster, so it must read as an
[[[DIVIDER]]]
8. THE FIRST DOCSTRING LINE IS A LIVE DISPLAY, not prose. `scripts/sources_menu.py`
   reads it with `ast.get_docstring` (never an import) and prints it verbatim
   beside the command word in the `sources` roster, so it must read as an
[[[REPLACE]]]
Target: scripts/connectors/README.md
[[[SEARCH]]]
connector that keeps its template's first line will display the template's
name in the `mcp` roster, which is how `gong.py` came to introduce itself as
`wallet.py`.
[[[DIVIDER]]]
connector that keeps its template's first line will display the template's
name in the `sources` roster, which is how `gong.py` came to introduce itself
as `wallet.py`.
[[[REPLACE]]]
Target: scripts/connectors/mcp.py
[[[SEARCH]]]
  python scripts/connectors/mcp.py <server>                       # LIST: initialize -> tools/list
  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
[[[DIVIDER]]]
  python scripts/connectors/mcp.py                                # IDENTITY: token state + usage; opens no socket
  python scripts/connectors/mcp.py <server>                       # LIST: initialize -> tools/list
  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
[[[REPLACE]]]
Target: scripts/connectors/mcp.py
[[[SEARCH]]]
def make_client(token):
    return httpx.Client(
[[[DIVIDER]]]
def identity():
    """No-argument mode: what this client holds, and what it still needs.

    THE FREED WORD ARRIVED EMPTY-HANDED (2026-08-25). `mcp` came free when the
    human roster was renamed to `sources`, and an alias pointing at a REQUIRED
    positional would have answered the freed word with argparse exit 2 -- a
    worse first keypress than the roster it replaced. Every other connector
    already has a bare-word identity walk; this is that walk, and it is why
    freeing the word and claiming it rode in the same car.

    IT REPORTS, IT NEVER ASSERTS (ATTRIBUTED-VOICE): a token RESOLVING is not a
    token being ACCEPTED. Only --check can say accepted, because only --check
    posts. resolve_token's own stderr clock note rides along unchanged, so an
    expired token says so HERE instead of arriving disguised as a 401 later.

    READ-ONLY BY CONSTRUCTION: no socket opens, no receipt is armed (so the
    atexit flush returns early and writes nothing), and no token VALUE is ever
    printed. Safe to echo as a `!` chisel-strike.
    """
    token_name, token = resolve_token()
    print("# mcp.py -- replay client for remote MCP servers (Streamable HTTP)")
    print(f"# protocol : {PROTOCOL_VERSION} (INFERRED until a GREEN --check)")
    if token:
        print(f"# token    : resolved from {token_name} (value never printed)")
        print("#            resolved is not accepted -- only --check posts")
    else:
        print("# token    : NONE. Tried, in order: MCP_BEARER_TOKEN,")
        print("#            MCP_TOKEN_FILE, BOTIFY_TOKEN_FILE,")
        print("#            ~/.config/pipulate/mcp_botify_token.json,")
        print("#            BOTIFY_API_TOKEN")
    print("#")
    print("# This client never guesses a server. Name one:")
    print("#   mcp <server> --check           envelope health; exit code is the answer")
    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")

def make_client(token):
    return httpx.Client(
[[[REPLACE]]]
Target: scripts/connectors/mcp.py
[[[SEARCH]]]
    parser.add_argument("server", help="MCP server URL, e.g. https://mcp.botify.com")
[[[DIVIDER]]]
    parser.add_argument("server", nargs="?", default=None,
                        help="MCP server URL, e.g. https://mcp.botify.com. "
                             "Omit for the identity walk.")
[[[REPLACE]]]
Target: scripts/connectors/mcp.py
[[[SEARCH]]]
    if args.check:
        sys.exit(check(args.server, args.token_env))
[[[DIVIDER]]]
    if args.server is None:
        identity()
        return

    if args.check:
        sys.exit(check(args.server, args.token_env))
[[[REPLACE]]]
```

**Car C — bank the earmark.** Small, separate, and vetoable. The line it edits describes the thing Car B just moved, so it is same-ride; item 1's `Corporate/` staleness was already stale before this ride and belongs to its own car.

```text
Target: foo_files.py
[[[SEARCH]]]
#   3. CONNECTOR ALIAS TRANSITION:
#      - Rename the human connector menu alias from `mcp` to `connect` (or `pipe` / `warp`) in `scripts/mcp_menu.py` and `flake.nix` to free bare `mcp` for the native Model Context Protocol client connector (`scripts/connectors/mcp.py`).
[[[DIVIDER]]]
#   3. CONNECTOR ALIAS TRANSITION -- DISCHARGED 2026-08-25, both clauses. The
#      roster became `sources` (scripts/mcp_menu.py -> scripts/sources_menu.py),
#      the registry dispatcher split off as `tools`, and `mcp` now aliases
#      scripts/connectors/mcp.py -- which grew a bare-word identity walk in the
#      SAME car, because a freed word pointed at a required positional would
#      have answered argparse exit 2 and been a worse keypress than the roster
#      it replaced. Kept as a dated tombstone rather than deleted: a numbering
#      gap in a list of eight reads as a lost item, which is a more expensive
#      confusion than six lines of receipt.
[[[REPLACE]]]
```

**IGNITION IS REQUIRED and it is not optional here.** `sources`, `tools`, and `alias mcp` live in the shellHook, which is read once at entry — an AFTER tap taken without it is a stale BEFORE wearing the AFTER's label. `scripts/sources_menu.py`, `boot_menu.py`, and `connectors/mcp.py` self-ignite (read from disk at call time), but you cannot type `sources` until the shell is re-entered.

Choreography: `git mv` → `patch`, `app`, `d`, `m` (Car B) → `patch`, `app`, `d`, `m` (Car C) → `blast` → then **`exit`, `nix develop`, press `2`** — that ignites the hook and renders the patched card in one move.

## 4. PROMPT

```text
The word split landed. Ignition was `exit` then `nix develop` then door 2, so the shell-word receipts in this compile are real AFTERs; the two Python files self-ignite and never needed it.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each:
- Probe 1: does flake.nix now show sources(), tools(), and alias mcp=, and is mcp() gone? Three lines is the pass. If it shows four, something did not replace and I want to know which.
- Probe 2: mcp_menu.py absent, sources_menu.py present. Anything else means the git mv did not run before the patches, and the sources_menu.py blocks would have been refused rather than misapplied -- say which happened.
- Probe 3: silence with stale_labels_exit=1 is the pass. If it prints a count line, name the file and I will sweep it.
- Probe 4: read the rendered panel. Confirm no overflow warning printed above it, and quote the new third FOOTER line back to me so I can see it is the tools line and not the mcp line.
- Probe 5: bare_exit=0 with the identity card is the pass. exit 2 with an argparse usage string means Car B's mcp.py blocks did not land; say so rather than ruling the car green off the other four.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Then the next discrete step, and only that one: the identity car. It is one story across four surfaces and I do not want it mixed with anything else.
1. The exact flake.nix edit that moves figlet and the Version line below the door-2 exit, read off probe 3's line numbers from the previous compile, plus what replaces them for a door-2 arrival. I want a line whose fields are all readings, not a boolean -- your `(nix) shell ready` shape, spelled out concretely with what each field actually reads from.
2. The same-car label sweep for that move, including flake.nix line 1367's learn prompt, which tells a newcomer to look for the figlet banner as a success checkpoint and becomes false the moment the banner moves to door 1 only.
3. Whether the door-2 card keeps three words and in what order, now that sources exists and pu is the one row that offers back the thing the human just declined.
4. Say explicitly what this car does NOT touch, so I can see the boundary before I apply it.

Hold the mcp roster row, the connectors/README.md "Current connectors" list, and the earmark item 1 Corporate correction for their own cars. Do not bundle them here.
```

## 5. EXTERNAL DELIVERABLES

None this turn.

**MikeLev.in**: 

**1: Probe**:

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

nothing to commit, working tree clean
(nix) pipulate $ rg -n -e '^ *(sources|tools|mcp)\(\)' -e '^ *alias mcp=' flake.nix
ls scripts/mcp_menu.py scripts/sources_menu.py 2>&1
rg -c -w mcp scripts/connectors/README.md scripts/boot_menu.py; echo "stale_labels_exit=$?"
COLUMNS=80 .venv/bin/python scripts/sources_menu.py
.venv/bin/python scripts/connectors/mcp.py; echo "bare_exit=$?"
1127:          mcp() {
ls: cannot access 'scripts/sources_menu.py': No such file or directory
scripts/mcp_menu.py
scripts/boot_menu.py:1
scripts/connectors/README.md:2
stale_labels_exit=0
.venv/bin/python: can't open file '/home/mike/repos/pipulate/scripts/sources_menu.py': [Errno 2] No such file or directory
usage: mcp.py [-h] [--check] [--dclass {D0,D1,D2}] [-n MAX] [--max-bytes MAX_BYTES]
              [--token-env TOKEN_ENV]
              server [tool] [args_json]
mcp.py: error: the following arguments are required: server
bare_exit=2
(nix) pipulate $ 
```

**2: Context**:

```text
# adhoc.txt    _   _   _ to set context____ _   _  ___  ____  _   <F5> Simpson Couch Gag Here (explain anything to the audience you feel needs it explained)
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  Trimming
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  
# Ad Hoc CHOP: The Not-Managed-by-Git Safe-for-Client-Data place  

# THE ROLLING PIN BOOK ORE SPINE / FODDER FOR THE BOOK
# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- The "Rolling Pin" that gives the 40K foot book-spine view of book-ore.
GLOSSARY.md                 # <-- I think this glossary goes well with the book-ore spine to do world building.
# scripts/articles/lsa.py     # <-- Useful for refining commands like `posts`, critical to Second Brain concept.

# THE QUIRKY AMIGA-LOVING HUMAN
~/repos/nixos/autognome.py  # <-- Letting the AIs really understand my environment (The Brave Little Tailor punches above Their Weight Class proving the dunning-kruger effect the gate-keeper's (lower-case) lament.)
init.lua                    # <-- Daily driver hot-keys that overlap with aliases in flake.nix

# THE HAND-CRANKED AGENTIC FRAMEWORK
prompt_foo.py               # <-- Prompt Fu compiler, makes the very README for AGENTS-like payload you're reading right now, but it needs to be more like that
foo_files.py                # <-- This is the router, evolving book outline and the things you pin-up to produced the recursive self-improvement loops

# MAIN ACTUATORS, IaC & NEGATIVE SPACE
apply.py                    # <-- How can "Web UI" ChatBots edit your code? With this Aider-inspired Player Piano patch applier.
.gitattributes              # <-- Model: understand that `nbstripout` and `jupytext` are both in play. Just talk the human through .ipynb patches.
.gitignore                  # <-- Creates "negative space" for sub-rep's to share parent environment and "snap" proprietary secret features into place.
flake.nix                   # <-- Solves world's WRITE ONCE RUN ANYWHERE problem like Java never could. Also resolves the bootstrap paradox.
requirements.in             # <-- All known dependencies and (necessary) version pinning. WORA gotcha's exposed.
__init__.py                 # <-- Master versioning
pyproject.toml              # <-- The PyPI Packaging details
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.
 
# CONTEXT PORTABILITY SYSTEM
scripts/foo_cartridge.py    # Needs description
scripts/foo_replay.py       # Needs description
 
# # FREQUENTLY USEFUL TO HAVE IN CONTEXT
release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.

# imports/voice_synthesis.py  # <-- The wand can talk to you
# 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.  ---

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

# server.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
  
# tools/scraper_tools.py
# tools/__init__.py
# tools/dom_tools.py
# tools/llm_optics.py
# scripts/walk.py

# assets/trails/first_context.yaml
# scripts/weblogin.py

# ! ls browser_cache/looking_at

# assets/installer/replay.sh
# scripts/mother_cat.py

# # `d`, `Shift`+`G`! I have to remember that.
# 
# ! { echo "== auth ruling witness =="; grep -c 'NOT distinct rides at the trail level' foo_files.py | sed 's/^/auth_ruling=/'; grep -c '^# assets/trails/' foo_files.py | sed 's/^/trail_lines=/'; }
# ! { echo "== botify guided captures =="; .venv/bin/python -c 'import glob,json; F=sorted(glob.glob("browser_cache/looking_at/app.botify.com/*/headers.json")); print("captures", len(F)); [print(json.dumps({"provenance": h.get("source_provenance"), "selection": h.get("header_selection"), "title_len": len(h.get("title") or ""), "login_marker": any(t in (h.get("final_url") or "").lower() for t in ("signin", "login", "sso"))})) for f in F for h in [json.load(open(f, encoding="utf-8"))]]'; }
# ! { echo "== non-ascii in url-bearing frontmatter, uncapped =="; .venv/bin/python -c 'import glob,os; P=sorted(glob.glob(os.path.expanduser("~/repos/trimnoir/_posts/*.md"))); print("scanned", len(P)); [print(ascii(os.path.basename(f)), ascii(l)) for f in P for l in open(f,encoding="utf-8").read().split(chr(10)) if l.startswith(("permalink:","canonical_url:")) and any(ord(c) > 127 for c in l)]'; }
# ! { echo "== router burden by region =="; .venv/bin/python -c 'p=open("foo_files.py",encoding="utf-8").read(); i=p.find("# " + "#todo #to-do"); j=p.find("XIX. THE PAINTBOX"); print("total_bytes", len(p)); print("earmark_bytes", (j-i) if 0 < i < j else "MARKER-MISS"); print("paintbox_bytes", (len(p)-j) if j > 0 else "MARKER-MISS")'; }
# foo_files.py
# GLOSSARY.md
# scripts/walk.py
# scripts/mother_cat.py
# scripts/walk_cartridge.py
# scripts/weblogin.py
# tools/scraper_tools.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py
# scripts/connectors/botify.py
# assets/trails/practice.yaml
# assets/trails/public_walk.yaml
# assets/trails/first_context.yaml
# # assets/trails/botify_pageworkers.yaml

# # --- PROBE ECHOES (verbatim from car 1) ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -30
# 
# # --- ACQUISITION: uncomment exactly ONE, chosen by the wc receipt ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 400
# 
# # --- THE JIRA LANE (deliberately leaner than this compile) ---
# scripts/connectors/README.md
# scripts/connectors/jira.py
# scripts/connectors/wallet.py
# init.lua
# flake.nix
# foo_files.py
# prompt_foo.py
# apply.py

# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,re,httpx; b=(os.getenv("JIRA_URL") or re.sub(r"/wiki/?$","",(os.getenv("CONFLUENCE_URL") or os.getenv("CONFLUENCE_BASE_URL") or "").rstrip("/"))).rstrip("/"); r=httpx.get(b+"/_edge/tenant_info",timeout=15); print("tenant_info",r.status_code,r.text[:160]); s=httpx.get(b+"/rest/api/3/serverInfo",timeout=15); print("serverInfo",s.status_code,(s.json().get("deploymentType") if s.status_code==200 else s.text[:80]))'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc

# ~/repos/nixos/autognome.py                 #  <-- More rare to have to include, but the true "top" of the muscle memory stack for day-to-day purposes
# ~/repos/nixos/configuration.nix            #  <-- "Global" IaC context (most of you won't have)
# ~/repos/nixos/blogs.nix
# ~/repos/nixos/packages.nix                 #  <-- Full disclosure on pre-flake IaC available apps.
# ~/repos/nixos/services.nix                 #  <-- Running Linux system services.
# ~/repos/nixos/ai-acceleration.nix          #  <-- Paid a lot for your hardware? We've got you covered.
# ~/repos/nixos/hardware-configuration.nix   #  <-- Automatically generated by Nix. The ultimate in IaC transparency.

# scripts/articles/common.py                   # <-- Self-explanatory
# scripts/articles/confluenceizer.py           # <-- Idempotent Jekyll-to-Confluence corporate wiki

# scripts/connectors/jira.py
# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,httpx; b=os.environ["JIRA_URL"].rstrip("/"); r=httpx.get(b+"/rest/api/3/myself",auth=httpx.BasicAuth(os.environ["JIRA_EMAIL"],os.environ["JIRA_TOKEN"]),headers={"Accept":"application/json"},timeout=15); print("myself_status="+str(r.status_code)); print("seraph="+str(r.headers.get("x-seraph-loginreason"))); print(r.text[:200])'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 30

# scripts/boot_menu.py  # [1,671 tokens | 6,636 bytes]
# scripts/mcp_menu.py
# assets/installer/mck.sh     # <-- THE LAUNCHER: curl -fsSL pipulate.com/mck.sh | bash
# assets/installer/install.sh   # The magic cookie: curl-distributed, git-free bootstrap

# ! COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
# ! .venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
# ! rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40

# scripts/mcp_menu.py
# scripts/boot_menu.py

! rg -n -e '^ *(sources|tools|mcp)\(\)' -e '^ *alias mcp=' flake.nix
! ls scripts/mcp_menu.py scripts/sources_menu.py 2>&1
! rg -c -w mcp scripts/connectors/README.md scripts/boot_menu.py; echo "stale_labels_exit=$?"
! COLUMNS=80 .venv/bin/python scripts/sources_menu.py
! .venv/bin/python scripts/connectors/mcp.py; echo "bare_exit=$?"
scripts/sources_menu.py
scripts/boot_menu.py
scripts/connectors/mcp.py
scripts/connectors/README.md
```

**3: Patches**: 

```diff
(nix) pipulate $ ahe
(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 $ git mv scripts/mcp_menu.py scripts/sources_menu.py
(nix) pipulate $ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    scripts/mcp_menu.py -> scripts/sources_menu.py

(nix) pipulate $ m
📝 Committing: refactor: Rename mcp_menu.py to sources_menu.py
[main 3fcad18b] refactor: Rename mcp_menu.py to sources_menu.py
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename scripts/{mcp_menu.py => sources_menu.py} (100%)
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/boot_menu.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/sources_menu.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/sources_menu.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/sources_menu.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/README.md'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/README.md'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/mcp.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/mcp.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/mcp.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/connectors/mcp.py'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index 64c66272..dfa2a320 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1110,23 +1110,46 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           alias gitops='(cd ~/repos/trimnoir && git commit --allow-empty -m "retry" && git push)'
           alias force='(cd ~/repos/trimnoir && git commit --allow-empty -m "retry" && git push)'
           alias isnix="if [ -n \"$IN_NIX_SHELL\" ]; then echo \"✓ In Nix shell v${version}\"; else echo \"✗ Not in Nix shell\"; fi"
-          # THE SECOND DOOR: bare `mcp` is the roster; `mcp <tool> [args]` is
-          # unchanged and still routes to cli.py's tool-call actuator. The
-          # word is not technically accurate for the connector rows -- it is
-          # the word people already reach for, and reaching for the right
-          # word beats being right about the wrong one.
+          # THE SECOND DOOR, SPLIT IN TWO (2026-08-25). One word was doing two
+          # 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
+          # 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:
           #
-          # FALL-THROUGH GUARANTEE: if scripts/mcp_menu.py has not landed,
-          # bare `mcp` behaves EXACTLY as it did before this function existed
-          # -- cli.py's own argparse error. A shell must never depend on a
-          # file that might not be there.
+          #   sources        the sources you can name (the roster)
+          #   tools          the registry tools you can call
+          #   tools <name>   call one
+          #   mcp <server>   the real Streamable-HTTP client (aliased below)
           #
-          # Also fixes a latent white-label bug: the old alias hardcoded
-          # ~/repos/pipulate, so `mcp` cd'd into the wrong (or missing)
-          # directory for anyone whose install folder is named otherwise.
-          mcp() {
-            if [ "$#" -eq 0 ] && [ -f "$PIPULATE_ROOT/scripts/mcp_menu.py" ]; then
-              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/mcp_menu.py"
+          # Discharges the CONNECTOR ALIAS TRANSITION earmark, whose text asked
+          # only that the roster be renamed so `mcp` came free. `sources` beats
+          # that earmark's own `connect` / `pipe` / `warp` for one reason: it
+          # names the OUTPUT CLASS rather than an action the command does not
+          # perform. The roster connects nothing; `warm` does.
+          #
+          # FALL-THROUGH GUARANTEE, and it now REFUSES instead of substituting:
+          # if the roster file has not landed, say so in one line. The old
+          # spelling fell through to `cli.py call` with no arguments, which
+          # answered a DIFFERENT QUESTION with an argparse error. A shell must
+          # never depend on a file that might not be there, and it must never
+          # quietly answer something else when that file is missing.
+          #
+          # FUNCTIONS, NOT ALIASES (THE THREE-TIER AMENDMENT): `tools` needs a
+          # branch, and both are typed by a human and never echoed as a `!`
+          # probe, so neither needs to be a packaged derivation.
+          sources() {
+            if [ -f "$PIPULATE_ROOT/scripts/sources_menu.py" ]; then
+              "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/sources_menu.py"
+            else
+              echo "sources: scripts/sources_menu.py has not landed in this checkout."
+            fi
+          }
+          tools() {
+            if [ "$#" -eq 0 ]; then
+              (cd "$PIPULATE_ROOT" && .venv/bin/python cli.py mcp-discover)
             else
               (cd "$PIPULATE_ROOT" && .venv/bin/python cli.py call "$@")
             fi
@@ -1169,6 +1192,13 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           alias sheets='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/sheets.py"'
           alias jira='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py"'
           alias slack='"$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/slack.py"'
+          # `mcp` NOW MEANS THE CLIENT, which is what the file has always been
+          # named. Freed 2026-08-25 when the roster became `sources`, and
+          # claimed in the SAME car so the word is never a hole. An ALIAS, not
+          # 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"'
           # 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.
@@ -1191,8 +1221,9 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # is unchanged for anyone who wants the browser and nothing else.
           #
           # A FUNCTION, not an alias: THE ALIAS-DISPATCH RULE says nothing can
-          # invoke an alias on a human's behalf, and mcp_menu.py's roster names
-          # this word to a reader who may reasonably expect it to be reachable.
+          # invoke an alias on a human's behalf, and sources_menu.py's roster
+          # names this word to a reader who may reasonably expect it to be
+          # reachable.
           warm() {
             if [ "$#" -eq 0 ]; then
               "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/wallet.py" check
diff --git a/scripts/boot_menu.py b/scripts/boot_menu.py
index a6803572..33046ab7 100644
--- a/scripts/boot_menu.py
+++ b/scripts/boot_menu.py
@@ -183,9 +183,9 @@ def main() -> int:
         print(f"Staying in the shell. Nothing started -- no {name}, no JupyterLab.")
         print()
         print("Three words get you everywhere:")
-        print("  learn   hand this whole workshop to an AI in a web chat")
-        print("  mcp     see what reaches outside this machine")
-        print(f"  pu      start {name} (long form: pipulate)")
+        print("  learn     hand this whole workshop to an AI in a web chat")
+        print("  sources   see what reaches outside this machine")
+        print(f"  pu        start {name} (long form: pipulate)")
     else:
         print(f"Starting {name}...")
     return choice
diff --git a/scripts/connectors/README.md b/scripts/connectors/README.md
index 83b7858b..20877036 100644
--- a/scripts/connectors/README.md
+++ b/scripts/connectors/README.md
@@ -26,9 +26,9 @@ has been fixed in the same helper in two files.
 7. COMPILE-LANE CAUTION in the docstring: if LIST/FETCH output can contain
    client identifiers, say so, and rely on pii_substitutions.txt coverage
    before any `!` invocation rides to a cloud chat window.
-8. THE FIRST DOCSTRING LINE IS A LIVE DISPLAY, not prose. `scripts/mcp_menu.py`
+8. THE FIRST DOCSTRING LINE IS A LIVE DISPLAY, not prose. `scripts/sources_menu.py`
    reads it with `ast.get_docstring` (never an import) and prints it verbatim
-   beside the command word in the `mcp` roster, so it must read as an
+   beside the command word in the `sources` roster, so it must read as an
    instruction to a newcomer who has never opened the file:
    `name.py — <verb phrase, one sentence, 61 chars or fewer>`, e.g. "Bring a
    Jira project, issue, or JQL search into context." The 61 is MEASURED, not
@@ -87,5 +87,5 @@ disambiguation table, keep the breadcrumbs. If an API's paging differs,
 write that API's paging — do not generalize another connector's. Then REWRITE
 the first docstring line before anything else (contract item 8): a copied
 connector that keeps its template's first line will display the template's
-name in the `mcp` roster, which is how `gong.py` came to introduce itself as
-`wallet.py`.
+name in the `sources` roster, which is how `gong.py` came to introduce itself
+as `wallet.py`.
diff --git a/scripts/connectors/mcp.py b/scripts/connectors/mcp.py
index f6c0213d..d5debe69 100644
--- a/scripts/connectors/mcp.py
+++ b/scripts/connectors/mcp.py
@@ -11,6 +11,7 @@ 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
   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
@@ -222,6 +223,45 @@ def resolve_token(token_env=None):
     return None, None
 
 
+def identity():
+    """No-argument mode: what this client holds, and what it still needs.
+
+    THE FREED WORD ARRIVED EMPTY-HANDED (2026-08-25). `mcp` came free when the
+    human roster was renamed to `sources`, and an alias pointing at a REQUIRED
+    positional would have answered the freed word with argparse exit 2 -- a
+    worse first keypress than the roster it replaced. Every other connector
+    already has a bare-word identity walk; this is that walk, and it is why
+    freeing the word and claiming it rode in the same car.
+
+    IT REPORTS, IT NEVER ASSERTS (ATTRIBUTED-VOICE): a token RESOLVING is not a
+    token being ACCEPTED. Only --check can say accepted, because only --check
+    posts. resolve_token's own stderr clock note rides along unchanged, so an
+    expired token says so HERE instead of arriving disguised as a 401 later.
+
+    READ-ONLY BY CONSTRUCTION: no socket opens, no receipt is armed (so the
+    atexit flush returns early and writes nothing), and no token VALUE is ever
+    printed. Safe to echo as a `!` chisel-strike.
+    """
+    token_name, token = resolve_token()
+    print("# mcp.py -- replay client for remote MCP servers (Streamable HTTP)")
+    print(f"# protocol : {PROTOCOL_VERSION} (INFERRED until a GREEN --check)")
+    if token:
+        print(f"# token    : resolved from {token_name} (value never printed)")
+        print("#            resolved is not accepted -- only --check posts")
+    else:
+        print("# token    : NONE. Tried, in order: MCP_BEARER_TOKEN,")
+        print("#            MCP_TOKEN_FILE, BOTIFY_TOKEN_FILE,")
+        print("#            ~/.config/pipulate/mcp_botify_token.json,")
+        print("#            BOTIFY_API_TOKEN")
+    print("#")
+    print("# This client never guesses a server. Name one:")
+    print("#   mcp <server> --check           envelope health; exit code is the answer")
+    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")
+
+
 def make_client(token):
     return httpx.Client(
         headers={
@@ -400,7 +440,9 @@ def check(server, token_env):
 def main():
     parser = argparse.ArgumentParser(
         description="Replay client and envelope witness for remote MCP servers.")
-    parser.add_argument("server", help="MCP server URL, e.g. https://mcp.botify.com")
+    parser.add_argument("server", nargs="?", default=None,
+                        help="MCP server URL, e.g. https://mcp.botify.com. "
+                             "Omit for the identity walk.")
     parser.add_argument("tool", nargs="?", default=None,
                         help="Tool name for CALL mode; omit for tools/list.")
     parser.add_argument("args_json", nargs="?", default="{}",
@@ -419,6 +461,10 @@ def main():
                              "MCP_BEARER_TOKEN, then BOTIFY_API_TOKEN).")
     args = parser.parse_args()
 
+    if args.server is None:
+        identity()
+        return
+
     if args.check:
         sys.exit(check(args.server, args.token_env))
 
diff --git a/scripts/sources_menu.py b/scripts/sources_menu.py
index 1e9f8fbe..43febabb 100644
--- a/scripts/sources_menu.py
+++ b/scripts/sources_menu.py
@@ -1,9 +1,9 @@
 #!/usr/bin/env python3
 """
-mcp_menu.py — what door 2 opens onto.
+sources_menu.py — what door 2 opens onto.
 
 boot_menu.py's door 2 drops the human into the Nix shell and tells them to
-type `mcp`. This is the roster they get: the commands that reach OUTSIDE
+type `sources`. This is the roster they get: the commands that reach OUTSIDE
 this machine, each row's description GENERATED from the target script's own
 module docstring rather than hand-authored here.
 
@@ -88,7 +88,7 @@ TAIL = [
 FOOTER = [
     "Add  --help  to any command above for its full usage.",
     "Type  learn  to hand this whole workshop to an AI in a web chat.",
-    "Type  mcp <tool_name>  to call a registered MCP tool directly.",
+    "Type  tools  to list registry tools, or  tools <name>  to call one.",
 ]
 
 
(nix) pipulate $ m
📝 Committing: feat: Rename `mcp` roster and clarify its usage
[main c846c766] feat: Rename `mcp` roster and clarify its usage
 5 files changed, 105 insertions(+), 28 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 1b25b082..849e529a 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -3092,8 +3092,15 @@ scripts/xp.py  # [672 tokens | 2,521 bytes]
 #      - Level 2: Shell script (`./briefing.sh`).
 #      - Level 3: Python script (`python scripts/briefing.py`).
 #      - Level 4: FastHTML app (`apps/050_briefing.py`).
-#   3. CONNECTOR ALIAS TRANSITION:
-#      - Rename the human connector menu alias from `mcp` to `connect` (or `pipe` / `warp`) in `scripts/mcp_menu.py` and `flake.nix` to free bare `mcp` for the native Model Context Protocol client connector (`scripts/connectors/mcp.py`).
+#   3. CONNECTOR ALIAS TRANSITION -- DISCHARGED 2026-08-25, both clauses. The
+#      roster became `sources` (scripts/mcp_menu.py -> scripts/sources_menu.py),
+#      the registry dispatcher split off as `tools`, and `mcp` now aliases
+#      scripts/connectors/mcp.py -- which grew a bare-word identity walk in the
+#      SAME car, because a freed word pointed at a required positional would
+#      have answered argparse exit 2 and been a worse keypress than the roster
+#      it replaced. Kept as a dated tombstone rather than deleted: a numbering
+#      gap in a list of eight reads as a lost item, which is a more expensive
+#      confusion than six lines of receipt.
 #   4. MULTI-DIRECTORY PLUGIN DISCOVERY:
 #      - Extend `server.py` app scanner to search `APP_SEARCH_PATHS` across `apps/`, `Notebooks/Corporate/apps/`, and `Notebooks/Personal/apps/`, sorting by numeric prefix so domain plugins (e.g. Botify Parameter Buster) cleanly decouple from core Pipulate. Later beat: extend the same scan to enrolled `Notebooks/Shared/<user>/apps/` so a teammate's tool rides in without a core commit.
 #   5. DIRECTORY-STRUCTURE FIGURATE ART (seeded 2026-07-25): register the
(nix) pipulate $ m
📝 Committing: chore: Update connector alias transition documentation and rename files
[main c8013dfc] chore: Update connector alias transition documentation and rename files
 1 file changed, 9 insertions(+), 2 deletions(-)
(nix) pipulate $ exit
exit
(sys) pipulate $ ndq
(nix) pipulate $ git push
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 48 threads
Compressing objects: 100% (15/15), done.
Writing objects: 100% (15/15), 8.14 KiB | 4.07 MiB/s, done.
Total 15 (delta 11), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (11/11), completed with 8 local objects.
To github.com:pipulate/pipulate.git
   14457f80..c8013dfc  main -> main
(nix) pipulate $
```

**4: Prompt**: The word split landed. Ignition was `exit` then `nix develop` then door 2, so the shell-word receipts in this compile are real AFTERs; the two Python files self-ignite and never needed it.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each:
- Probe 1: does flake.nix now show sources(), tools(), and alias mcp=, and is mcp() gone? Three lines is the pass. If it shows four, something did not replace and I want to know which.
- Probe 2: mcp_menu.py absent, sources_menu.py present. Anything else means the git mv did not run before the patches, and the sources_menu.py blocks would have been refused rather than misapplied -- say which happened.
- Probe 3: silence with stale_labels_exit=1 is the pass. If it prints a count line, name the file and I will sweep it.
- Probe 4: read the rendered panel. Confirm no overflow warning printed above it, and quote the new third FOOTER line back to me so I can see it is the tools line and not the mcp line.
- Probe 5: bare_exit=0 with the identity card is the pass. exit 2 with an argparse usage string means Car B's mcp.py blocks did not land; say so rather than ruling the car green off the other four.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Then the next discrete step, and only that one: the identity car. It is one story across four surfaces and I do not want it mixed with anything else.
1. The exact flake.nix edit that moves figlet and the Version line below the door-2 exit, read off probe 3's line numbers from the previous compile, plus what replaces them for a door-2 arrival. I want a line whose fields are all readings, not a boolean -- your `(nix) shell ready` shape, spelled out concretely with what each field actually reads from.
2. The same-car label sweep for that move, including flake.nix line 1367's learn prompt, which tells a newcomer to look for the figlet banner as a success checkpoint and becomes false the moment the banner moves to door 1 only.
3. Whether the door-2 card keeps three words and in what order, now that sources exists and pu is the one row that offers back the thing the human just declined.
4. Say explicitly what this car does NOT touch, so I can see the boundary before I apply it.

Hold the mcp roster row, the connectors/README.md "Current connectors" list, and the earmark item 1 Corporate correction for their own cars. Do not bundle them here.

**5: Deliverables**: A step closer.

**Opus 5 Max**: Context verified.

## The ruling — five for five, and the taps are clean

All five echoed lines appear in the Manifest's LIVE COMMAND RECEIPTS, so every ruling below is a real AFTER from the compile lane, taken after your `exit` → `ndq` ignition.

**Probe 1 — PASS, three lines.** `1143: sources()`, `1150: tools()`, `1201: alias mcp=`. `mcp()` is gone. Not four, so nothing failed to replace. Bonus reading: the +16 line displacement (`mcp()` was at 1127, `sources()` is at 1143) is consistent with the comment block growing, and `alias mcp=` landing at 1201 puts it inside the connector alias run where it belongs.

**Probe 2 — PASS.** `mcp_menu.py` absent, `sources_menu.py` present. The `git mv` ran before the patches, which is why the two `sources_menu.py` blocks applied instead of being refused.

**Probe 3 — PASS, and it is the receipt shape the constitution was amended for.** Silence with `stale_labels_exit=1`. `rg` found zero word-boundaried `mcp` in `connectors/README.md` or `boot_menu.py` — down from `2` and `1` in your hand-run BEFORE. This is a probe whose success *is* silence, and the SILENT-SUCCESS RECEIPT amendment is why it landed in the Manifest at all instead of vanishing.

**Probe 4 — PASS, both halves.** No overflow warning above the panel, so the guard installed two rides ago reads clean against the new roster. The third FOOTER line, quoted back verbatim:

> `Type  tools  to list registry tools, or  tools <name>  to call one.`

That is the tools line, not the mcp line.

**Probe 5 — PASS, and it flipped a second branch you did not ask for.** `bare_exit=0` with the identity card. The argparse usage string is gone. And riding on stderr:

> `# mcp token clock: EXPIRED 1630896s ago (life was 300s); refresh_token present: yes; re-mint with python scripts/connectors/mcp_warm.py`

That is `_expiry_note`'s EXPIRED branch firing at exactly the moment its docstring predicted — "an expired token says so HERE instead of arriving disguised as a 401 later." 1,630,896 seconds is 18.9 days, which matches the Aug 6 `--refresh` in the ledger. The identity walk is doing the job it was written for on its first flight.

---

## The thing that fits no branch: the router kept a ghost

```text
⚠️  TOPOLOGICAL INTEGRITY ALERT (1 broken of 56 candidates):
  • scripts/mcp_menu.py
```

Chapter XVIII of `foo_files.py` still carries `# scripts/mcp_menu.py` in the connector roster. The `git mv` moved the file; the router's own claim on it did not move in the same car. Two independent channels caught it in this compile:

1. The integrity checker, firing on a **true positive** — and firing only because the SCOPE PARITY fix of 2026-08-21 made it read the spliced overlay body rather than the tracked one.
2. The Paintbox, which now lists `# scripts/sources_menu.py  # [2,172 tokens | 8,919 bytes]` as an unclaimed color — visible in this compile's git-diff telemetry.

One line, two symptoms, and it is the previous car's SAME-CAR LABEL debt rather than a new story. It rides below as **Car A**, explicitly vetoable.

**One non-finding, so nobody hunts it:** the Telemetry section shows only the `foo_files.py` paintbox churn. `git diff HEAD` found working-tree changes (the compiler's own token-count rewrite), so it never fell back to `HEAD~1..HEAD` and the two commits from your ride are invisible here. That is `diff_label` behaving as documented, not a missing patch.

---

## The identity car

### 1. The flake edit, and what replaces the banner

**Position, corrected from my last turn.** I proposed printing the readings line *inside* the door-2 branch. That is wrong: `boot_menu.py` prints the card and returns before `runScript` resumes, so the readings would land *below* the card, pushing the actionable words away from the cursor. Instead the readings line takes the figlet's **exact position** — above the threshold, on every path — and the figlet moves down past the door-2 exit. One swap, two blocks.

**The witness argument I made last turn was also too strong, and it works out in your favour.** `runScript` is a `writeShellScriptBin` invoked by the *last* line of each shellHook, so **any** output from it witnesses that the whole hook parsed. The HALF-EXECUTED HOOK failure prints nothing here at all. Position within `runScript` therefore barely matters, and the in-place swap costs no witness strength.

**Every field, and what it reads from:**

| field | reading | source |
|---|---|---|
| `nix (Determinate Nix 3.x.y) 2.x.y` | `nix --version`, last line | the binary itself — **discriminates DetSys from generic Nix for free** |
| `Python 3.12.11` | `python -V` | the activated `.venv`, so it reports the interpreter that will actually run |
| `v2.44` | `${versionNumber}` | `__init__.py`, read by Nix at eval time |
| `/home/mike/repos/pipulate` | `$PWD` | the shell — and the whitelabel name shows through without asserting it |

`Generic nix present: True` names a state nothing observed. `nix (Determinate Nix 3.5.2)` is an observation, and it carries strictly more information than the boolean it replaces. Its **silence is also a reading**: in the world where the hook died early, nothing prints.

`LD_LIBRARY_PATH=""` is load-bearing, not decoration — THE UNEXPORTED-SHIM RULE. The `nix()` rpath shim is a shell *function* in `miscSetupLogic`; `runScript` is a *child process* and inherits the polluted path without the shim.

### 2. The same-car label sweep

- **`flake.nix` learn prompt (was 1367).** `(the figlet banner, the JupyterLab URL, the spoken voice greeting)` becomes false for door-2 arrivals the moment the banner moves. Patched — and while the string is open, it gains the **two-door menu**, which the prompt never mentioned at all. A newcomer following Yen Sid-ton currently hits that panel with no warning. Free fix, same string.
- **`scripts/boot_menu.py`** — the card, below.
- **`figlet` in `commonPackages` (line 471)** stays. Door 1 still needs it.
- **`PROPER_APP_NAME`** stays computed where it is. Probe 3 from the previous compile established it has exactly one consumer (the figlet), and both live in one process, so the move strands nothing.

### 3. The card: three words, reordered, and one false claim removed

Keep three. `pu` was already last — the real defect is elsewhere.

**"Three words get you everywhere" is not true.** `foo`, `ahc`, `warm`, `weblogin`, `article`, `blast` and now `tools` all exist and none are listed. A claim that over-reaches on a first-contact surface is the same disease as the banner asserting an identity nobody asked for.

**New order: `sources` → `learn` → `pu`.** A scope ladder rather than three categories: *stay here and look around* → *hand it off elsewhere* → *undo the choice you just made*. `sources` goes first because it is the only one that keeps the human moving inside the workshop, which is your stated goal — less between intro and it just working. `pu` stays last and now reads as a reversal rather than an offer.

Deliberately **not** added: a fourth row for `tools`. The `sources` footer already names it, and four words is not three.

### 4. What this car does NOT touch

- `boot_menu.py`'s panel title `{name} :: pick a door` and `[1] Start {name}` — both legitimately name what door 1 starts, and both already derive from `whitelabel.txt`.
- `Staying in the shell. Nothing started -- no {name}, no JupyterLab.` — a reading of what did not happen.
- **The `learn` rename.** It fails the mechanical test and its output is a token-budget ledger at minute zero, but that is a *vocabulary* story touching the flake function, the card, the `sources` footer and yesterday's published article. Mixing it here breaks your own constraint.
- The `mcp` roster row, `connectors/README.md`'s "Current connectors" list, earmark item 1's `Corporate/` staleness — held, as you asked.
- The door-1 TTS greeting and the `install.sh` banner.
- `.#quiet` — never reaches `runScript`, so the agent lane is unaffected and has never seen a figlet.

---

## 1. PROBES

```bash
rg -n -e '^ *figlet "' -e '^ *echo "Version:' -e 'NIX_READING' flake.nix
rg -n -e 'get you everywhere' -e 'two-door menu' -e 'to start from' flake.nix scripts/boot_menu.py
LD_LIBRARY_PATH="" nix eval .#devShells.x86_64-linux.default.drvPath; echo "eval_exit=$?"
V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1); P=$(python -V 2>&1); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$PWD"); printf '%s\nchars=%s\n' "$L" "${#L}"
```

Probe 1 is a **displacement** receipt, not an extent one: BEFORE is 2 lines at 620/621; AFTER should be 5 lines, with three `NIX_READING` hits where the banner used to be and `figlet`/`echo "Version:` displaced *below* the `BOOT_CHOICE` gate. Probe 2 discriminates cleanly — `get you everywhere` must vanish and two new strings appear, so silence-on-all-three would mean nothing landed. Probe 3 is the one that matters most: it forces evaluation of the `default` devShell (never `quiet`, which carries no `runScript`), so `eval_exit=0` proves `${versionNumber}` is in scope and a **changed drv hash** proves the patched text is what a fresh `nix develop` would instantiate — the CROSS-PLATFORM EVAL RULE's gift, an ignition witness without entering a shell. `LD_LIBRARY_PATH=""` is mandatory there for the same reason it is in the patch.

**Probe 4 is a field preview, not a straddle, and I am labelling it so rather than letting it pass as one.** Its BEFORE and AFTER are expected to be *identical* — it renders the exact line the patch will print and reports its width, so the 80-column lesson from two rides ago gets applied before the string ships instead of after. Its green is uninformative about the patch; probes 1–3 carry that.

## 2. NEXT CONTEXT

```text
! rg -n -e '^ *figlet "' -e '^ *echo "Version:' -e 'NIX_READING' flake.nix
! rg -n -e 'get you everywhere' -e 'two-door menu' -e 'to start from' flake.nix scripts/boot_menu.py
! LD_LIBRARY_PATH="" nix eval .#devShells.x86_64-linux.default.drvPath; echo "eval_exit=$?"
! V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1); P=$(python -V 2>&1); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$PWD"); printf '%s\nchars=%s\n' "$L" "${#L}"
flake.nix
scripts/boot_menu.py
foo_files.py
prompt_foo.py
apply.py
__init__.py
scripts/sources_menu.py
```

**Drop ballast — this ran 261k tokens and the next car touches three files.** Safe to comment out for one turn: `~/repos/nixos/autognome.py`, `init.lua`, `release.py`, `GLOSSARY.md`, `cli.py`, `scripts/xp.py`, `scripts/ai.py`, `scripts/foo_cartridge.py`, `scripts/foo_replay.py`, `scripts/weblogin.py`, `scripts/crawl.py`, `scripts/connectors/mcp.py`, `scripts/connectors/README.md`, `requirements.in`, `pyproject.toml`, `.gitattributes`, `.gitignore`. That is roughly 90k of the payload.

## 3. PATCHES

**Car A — close the previous car's label debt.** One line. Veto costs nothing; the alert simply keeps firing.

```text
Target: foo_files.py
[[[SEARCH]]]
# scripts/mcp_menu.py
[[[DIVIDER]]]
# scripts/sources_menu.py
[[[REPLACE]]]
```

**Car B — the identity car.** One commit story across two files.

```text
Target: flake.nix
[[[SEARCH]]]
          figlet "$PROPER_APP_NAME"
          echo "Version: ${version}"
[[[DIVIDER]]]
          # THE BANNER MOVED TO DOOR 1 (2026-08-25). The figlet printed HERE,
          # ABOVE the threshold, so the human who was one keypress away from
          # saying "do not start the app" got a full-width ASCII assertion of
          # that app's identity first. The banner is the curtain going up on
          # the app; it belongs on the path where the app actually starts, and
          # it now renders just below the BOOT_CHOICE exit. PROPER_APP_NAME
          # stays computed here -- it is the figlet's only consumer and both
          # live in this one process, so the move strands nothing.
          #
          # WHAT REPLACES IT IS A READING, NEVER A BOOLEAN. "nix present: True"
          # names a state nothing observed; `nix --version` is an observation,
          # and it discriminates Determinate Nix from generic Nix for free --
          # exactly the fact a first-contact reader needs and cannot get from a
          # boolean. Every field is read at this moment from a named source:
          # nix from the binary, python from the activated venv, the version
          # from __init__.py at flake eval, the path from the shell.
          #
          # ITS SILENCE IS ALSO A READING. runScript is invoked by the LAST
          # line of each shellHook, so ANY output from it witnesses that the
          # whole hook parsed -- the HALF-EXECUTED HOOK failure prints nothing
          # here at all. That witness used to be the figlet's job; it did not
          # disappear, it changed hands.
          #
          # LD_LIBRARY_PATH="" IS LOAD-BEARING (THE UNEXPORTED-SHIM RULE): the
          # nix() rpath shim is a shell FUNCTION defined in miscSetupLogic, and
          # this script is a CHILD PROCESS, so it inherits the polluted path
          # and not the shim. The inline clear is the prescribed spelling and
          # is a no-op on a clean shell.
          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1)
          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
          PY_READING=$(python -V 2>&1)
          if [ -z "$PY_READING" ]; then PY_READING="python: no reading"; fi
          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD"
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
          # Automatically start JupyterLab in background and server in foreground
[[[DIVIDER]]]
          # DOOR 1 ONLY: the banner, moved down from above the threshold on
          # 2026-08-25. Everything below this line runs only when the human
          # chose to start the app -- or when boot_menu.py is absent and the
          # FALL-THROUGH GUARANTEE puts us on the pre-menu path, where the
          # banner printed unconditionally anyway. The full version string
          # with its description rides here rather than in the readings line
          # above, because this is the one surface whose entire job is to name
          # the thing that is starting.
          figlet "$PROPER_APP_NAME"
          echo "Version: ${version}"

          # Automatically start JupyterLab in background and server in foreground
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
(the figlet banner, the JupyterLab URL, the spoken voice greeting)
[[[DIVIDER]]]
(the one-line environment readings, the two-door menu where they press 1, the figlet banner once the app starts, the JupyterLab URL, the spoken voice greeting)
[[[REPLACE]]]
Target: scripts/boot_menu.py
[[[SEARCH]]]
        print("Three words get you everywhere:")
        print("  learn     hand this whole workshop to an AI in a web chat")
        print("  sources   see what reaches outside this machine")
        print(f"  pu        start {name} (long form: pipulate)")
[[[DIVIDER]]]
        print("Three words to start from:")
        print("  sources   see what this shell can reach outside this machine")
        print("  learn     hand this whole workshop to an AI in a web chat")
        print(f"  pu        change your mind and start {name} after all")
[[[REPLACE]]]
```

**IGNITION IS REQUIRED, and it splits.** Probes 1–3 are real AFTERs without it — probe 3 evaluates the patched `runScript` text at eval time, so a changed drv hash is the ignition witness. But the *rendered* line and the *rendered* card need `exit`, then `nix develop`, then **press 2** — and once more pressing **1** if you want to see the figlet in its new home before trusting the move.

Choreography: `patch`, `app`, `d`, `m` (Car A) → `patch`, `app`, `d`, `m` (Car B) → `blast` → `exit`, `nix develop`, `2`.

## 4. PROMPT

```text
The identity car landed. Ignition was `exit` then `nix develop`, and I pressed both doors. Probes 1-3 are real AFTERs; probe 4 is a field preview whose before and after are expected to be identical.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each:
- Probe 1: five lines is the pass -- three NIX_READING hits where the banner was, and figlet plus echo "Version: displaced BELOW the BOOT_CHOICE gate. Give me the line numbers and say which direction each moved. Two lines means nothing landed; four means one block failed and I want to know which.
- Probe 2: `get you everywhere` must be gone and `two-door menu` and `to start from` must both be present. If all three are silent that is evidence about my patterns before it is evidence about the files, and say which you concluded.
- Probe 3: eval_exit=0 proves versionNumber is in scope. Compare the drv hash to nothing -- I have no BEFORE for it -- so rule only on the exit code and say so plainly rather than reading a hash you cannot compare.
- Probe 4: quote the rendered line and its char count back to me. Under 80 is the pass. If it is over, name by how much and which field to cut.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Here is what I saw with my own eyes on re-entry, which no probe can witness:

[paste the door-2 output here, and the door-1 output here]

Then the next discrete step, and only that one: the vocabulary car. `learn` fails the mechanical test -- nobody learns, a payload compiles and a clipboard fills -- and what a newcomer actually sees is the Rich Payload Ledger and the console summary, which is a token-budget accounting table answering "teach me."

1. The word. Give me your one pick with the reason, not a list. It has to work as a verb a stranger types at a prompt.
2. Whether the fix is the rename, the --quiet on prompt_foo.py that gates step 5 only, or both in one car -- and if both, say why they are one story rather than two.
3. If --quiet is in scope, the exact boundary: name every line that must stay loud and which step prints it, so I can see that the secrets tripwire and the disclosure receipt are structurally out of reach of the flag.
4. The complete same-car label sweep, including yesterday's published article if the word changes.
5. Say explicitly what that car does NOT touch.

Hold the mcp roster row, the connectors/README.md "Current connectors" list, and the earmark item 1 Corporate correction for their own cars. Do not bundle them here.
```

## 5. EXTERNAL DELIVERABLES

None this turn.

**MikeLev.in**: 

**1: Probe**:

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

nothing to commit, working tree clean
(nix) pipulate $ rg -n -e '^ *figlet "' -e '^ *echo "Version:' -e 'NIX_READING' flake.nix
rg -n -e 'get you everywhere' -e 'two-door menu' -e 'to start from' flake.nix scripts/boot_menu.py
LD_LIBRARY_PATH="" nix eval .#devShells.x86_64-linux.default.drvPath; echo "eval_exit=$?"
V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1); P=$(python -V 2>&1); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$PWD"); printf '%s\nchars=%s\n' "$L" "${#L}"
620:          figlet "$PROPER_APP_NAME"
621:          echo "Version: ${version}"
scripts/boot_menu.py
185:        print("Three words get you everywhere:")
"/nix/store/fr5kx4qdbawafg13zm4widda3bzg8g46-nix-shell.drv"
eval_exit=0
nix (Nix) 2.25.0pre20240910_b9d3cdfb · Python 3.12.13 · v2.44 · /home/mike/repos/pipulate
chars=89
(nix) pipulate $ 
```

**2: Context**:

```text
# adhoc.txt    _   _   _ to set context____ _   _  ___  ____  _   <F5> Simpson Couch Gag Here (explain anything to the audience you feel needs it explained)
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  MCP Cleanup
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  
# Ad Hoc CHOP: The Not-Managed-by-Git Safe-for-Client-Data place  

# THE ROLLING PIN BOOK ORE SPINE / FODDER FOR THE BOOK
# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- The "Rolling Pin" that gives the 40K foot book-spine view of book-ore.
GLOSSARY.md                 # <-- I think this glossary goes well with the book-ore spine to do world building.
# scripts/articles/lsa.py     # <-- Useful for refining commands like `posts`, critical to Second Brain concept.

# THE QUIRKY AMIGA-LOVING HUMAN
~/repos/nixos/autognome.py  # <-- Letting the AIs really understand my environment (The Brave Little Tailor punches above Their Weight Class proving the dunning-kruger effect the gate-keeper's (lower-case) lament.)
init.lua                    # <-- Daily driver hot-keys that overlap with aliases in flake.nix

# THE HAND-CRANKED AGENTIC FRAMEWORK
prompt_foo.py               # <-- Prompt Fu compiler, makes the very README for AGENTS-like payload you're reading right now, but it needs to be more like that
foo_files.py                # <-- This is the router, evolving book outline and the things you pin-up to produced the recursive self-improvement loops

# MAIN ACTUATORS, IaC & NEGATIVE SPACE
apply.py                    # <-- How can "Web UI" ChatBots edit your code? With this Aider-inspired Player Piano patch applier.
.gitattributes              # <-- Model: understand that `nbstripout` and `jupytext` are both in play. Just talk the human through .ipynb patches.
.gitignore                  # <-- Creates "negative space" for sub-rep's to share parent environment and "snap" proprietary secret features into place.
flake.nix                   # <-- Solves world's WRITE ONCE RUN ANYWHERE problem like Java never could. Also resolves the bootstrap paradox.
requirements.in             # <-- All known dependencies and (necessary) version pinning. WORA gotcha's exposed.
__init__.py                 # <-- Master versioning
pyproject.toml              # <-- The PyPI Packaging details
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.
 
# CONTEXT PORTABILITY SYSTEM
scripts/foo_cartridge.py    # Needs description
scripts/foo_replay.py       # Needs description
 
# # FREQUENTLY USEFUL TO HAVE IN CONTEXT
release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.

# imports/voice_synthesis.py  # <-- The wand can talk to you
# 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.  ---

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

# server.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
  
# tools/scraper_tools.py
# tools/__init__.py
# tools/dom_tools.py
# tools/llm_optics.py
# scripts/walk.py

# assets/trails/first_context.yaml
# scripts/weblogin.py

# ! ls browser_cache/looking_at

# assets/installer/replay.sh
# scripts/mother_cat.py

# # `d`, `Shift`+`G`! I have to remember that.
# 
# ! { echo "== auth ruling witness =="; grep -c 'NOT distinct rides at the trail level' foo_files.py | sed 's/^/auth_ruling=/'; grep -c '^# assets/trails/' foo_files.py | sed 's/^/trail_lines=/'; }
# ! { echo "== botify guided captures =="; .venv/bin/python -c 'import glob,json; F=sorted(glob.glob("browser_cache/looking_at/app.botify.com/*/headers.json")); print("captures", len(F)); [print(json.dumps({"provenance": h.get("source_provenance"), "selection": h.get("header_selection"), "title_len": len(h.get("title") or ""), "login_marker": any(t in (h.get("final_url") or "").lower() for t in ("signin", "login", "sso"))})) for f in F for h in [json.load(open(f, encoding="utf-8"))]]'; }
# ! { echo "== non-ascii in url-bearing frontmatter, uncapped =="; .venv/bin/python -c 'import glob,os; P=sorted(glob.glob(os.path.expanduser("~/repos/trimnoir/_posts/*.md"))); print("scanned", len(P)); [print(ascii(os.path.basename(f)), ascii(l)) for f in P for l in open(f,encoding="utf-8").read().split(chr(10)) if l.startswith(("permalink:","canonical_url:")) and any(ord(c) > 127 for c in l)]'; }
# ! { echo "== router burden by region =="; .venv/bin/python -c 'p=open("foo_files.py",encoding="utf-8").read(); i=p.find("# " + "#todo #to-do"); j=p.find("XIX. THE PAINTBOX"); print("total_bytes", len(p)); print("earmark_bytes", (j-i) if 0 < i < j else "MARKER-MISS"); print("paintbox_bytes", (len(p)-j) if j > 0 else "MARKER-MISS")'; }
# foo_files.py
# GLOSSARY.md
# scripts/walk.py
# scripts/mother_cat.py
# scripts/walk_cartridge.py
# scripts/weblogin.py
# tools/scraper_tools.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py
# scripts/connectors/botify.py
# assets/trails/practice.yaml
# assets/trails/public_walk.yaml
# assets/trails/first_context.yaml
# # assets/trails/botify_pageworkers.yaml

# # --- PROBE ECHOES (verbatim from car 1) ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -30
# 
# # --- ACQUISITION: uncomment exactly ONE, chosen by the wc receipt ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 400
# 
# # --- THE JIRA LANE (deliberately leaner than this compile) ---
# scripts/connectors/README.md
# scripts/connectors/jira.py
# scripts/connectors/wallet.py
# init.lua
# flake.nix
# foo_files.py
# prompt_foo.py
# apply.py

# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,re,httpx; b=(os.getenv("JIRA_URL") or re.sub(r"/wiki/?$","",(os.getenv("CONFLUENCE_URL") or os.getenv("CONFLUENCE_BASE_URL") or "").rstrip("/"))).rstrip("/"); r=httpx.get(b+"/_edge/tenant_info",timeout=15); print("tenant_info",r.status_code,r.text[:160]); s=httpx.get(b+"/rest/api/3/serverInfo",timeout=15); print("serverInfo",s.status_code,(s.json().get("deploymentType") if s.status_code==200 else s.text[:80]))'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc

# ~/repos/nixos/autognome.py                 #  <-- More rare to have to include, but the true "top" of the muscle memory stack for day-to-day purposes
# ~/repos/nixos/configuration.nix            #  <-- "Global" IaC context (most of you won't have)
# ~/repos/nixos/blogs.nix
# ~/repos/nixos/packages.nix                 #  <-- Full disclosure on pre-flake IaC available apps.
# ~/repos/nixos/services.nix                 #  <-- Running Linux system services.
# ~/repos/nixos/ai-acceleration.nix          #  <-- Paid a lot for your hardware? We've got you covered.
# ~/repos/nixos/hardware-configuration.nix   #  <-- Automatically generated by Nix. The ultimate in IaC transparency.

# scripts/articles/common.py                   # <-- Self-explanatory
# scripts/articles/confluenceizer.py           # <-- Idempotent Jekyll-to-Confluence corporate wiki

# scripts/connectors/jira.py
# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,httpx; b=os.environ["JIRA_URL"].rstrip("/"); r=httpx.get(b+"/rest/api/3/myself",auth=httpx.BasicAuth(os.environ["JIRA_EMAIL"],os.environ["JIRA_TOKEN"]),headers={"Accept":"application/json"},timeout=15); print("myself_status="+str(r.status_code)); print("seraph="+str(r.headers.get("x-seraph-loginreason"))); print(r.text[:200])'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 30

# scripts/boot_menu.py  # [1,671 tokens | 6,636 bytes]
# scripts/mcp_menu.py
# assets/installer/mck.sh     # <-- THE LAUNCHER: curl -fsSL pipulate.com/mck.sh | bash
# assets/installer/install.sh   # The magic cookie: curl-distributed, git-free bootstrap

# ! COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
# ! .venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
# ! rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40

# scripts/mcp_menu.py
# scripts/boot_menu.py

! rg -n -e '^ *figlet "' -e '^ *echo "Version:' -e 'NIX_READING' flake.nix
! rg -n -e 'get you everywhere' -e 'two-door menu' -e 'to start from' flake.nix scripts/boot_menu.py
! LD_LIBRARY_PATH="" nix eval .#devShells.x86_64-linux.default.drvPath; echo "eval_exit=$?"
! V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1); P=$(python -V 2>&1); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$PWD"); printf '%s\nchars=%s\n' "$L" "${#L}"
flake.nix
scripts/boot_menu.py
foo_files.py
prompt_foo.py
apply.py
__init__.py
scripts/sources_menu.py
```

**3: Patches**: 

```diff
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 6e84942d..701fb283 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -2049,7 +2049,7 @@ scripts/release/version_sync.py  # <-- Needs to be wrapped into release.py and e
 # ============================================================================
 
 # THE CONNECTORS (WET single-file API gateways; contract in the README)
-# scripts/mcp_menu.py
+# scripts/sources_menu.py
 # scripts/connectors/README.md
 # scripts/connectors/gmail.py
 # scripts/connectors/confluence.py
(nix) pipulate $ m
📝 Committing: chore: Rename scripts/mcp_menu.py to scripts/sources_menu.py
[main 58e5a505] chore: Rename scripts/mcp_menu.py to scripts/sources_menu.py
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/boot_menu.py'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index dfa2a320..cd2fdaf6 100644
--- a/flake.nix
+++ b/flake.nix
@@ -617,8 +617,39 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # preserved if/when the directory is transformed into a git repo
           APP_NAME=$(cat whitelabel.txt)
           PROPER_APP_NAME=$(echo "$APP_NAME" | awk '{print toupper(substr($0,1,1)) tolower(substr($0,2))}')
-          figlet "$PROPER_APP_NAME"
-          echo "Version: ${version}"
+          # THE BANNER MOVED TO DOOR 1 (2026-08-25). The figlet printed HERE,
+          # ABOVE the threshold, so the human who was one keypress away from
+          # saying "do not start the app" got a full-width ASCII assertion of
+          # that app's identity first. The banner is the curtain going up on
+          # the app; it belongs on the path where the app actually starts, and
+          # it now renders just below the BOOT_CHOICE exit. PROPER_APP_NAME
+          # stays computed here -- it is the figlet's only consumer and both
+          # live in this one process, so the move strands nothing.
+          #
+          # WHAT REPLACES IT IS A READING, NEVER A BOOLEAN. "nix present: True"
+          # names a state nothing observed; `nix --version` is an observation,
+          # and it discriminates Determinate Nix from generic Nix for free --
+          # exactly the fact a first-contact reader needs and cannot get from a
+          # boolean. Every field is read at this moment from a named source:
+          # nix from the binary, python from the activated venv, the version
+          # from __init__.py at flake eval, the path from the shell.
+          #
+          # ITS SILENCE IS ALSO A READING. runScript is invoked by the LAST
+          # line of each shellHook, so ANY output from it witnesses that the
+          # whole hook parsed -- the HALF-EXECUTED HOOK failure prints nothing
+          # here at all. That witness used to be the figlet's job; it did not
+          # disappear, it changed hands.
+          #
+          # LD_LIBRARY_PATH="" IS LOAD-BEARING (THE UNEXPORTED-SHIM RULE): the
+          # nix() rpath shim is a shell FUNCTION defined in miscSetupLogic, and
+          # this script is a CHILD PROCESS, so it inherits the polluted path
+          # and not the shim. The inline clear is the prescribed spelling and
+          # is a no-op on a clean shell.
+          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1)
+          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
+          PY_READING=$(python -V 2>&1)
+          if [ -z "$PY_READING" ]; then PY_READING="python: no reading"; fi
+          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD"
           # --- JupyterLab Local Configuration ---
           export JUPYTER_CONFIG_DIR="$(pwd)/.jupyter"
           # Install Python packages from requirements.txt
@@ -708,6 +739,17 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
             # authorized failed to start.
             exit 0
           fi
+          # DOOR 1 ONLY: the banner, moved down from above the threshold on
+          # 2026-08-25. Everything below this line runs only when the human
+          # chose to start the app -- or when boot_menu.py is absent and the
+          # FALL-THROUGH GUARANTEE puts us on the pre-menu path, where the
+          # banner printed unconditionally anyway. The full version string
+          # with its description rides here rather than in the readings line
+          # above, because this is the one surface whose entire job is to name
+          # the thing that is starting.
+          figlet "$PROPER_APP_NAME"
+          echo "Version: ${version}"
+
           # Automatically start JupyterLab in background and server in foreground
           # Start JupyterLab in a tmux session
           # NOTE: kill and launch stay PAIRED inside the branch. Splitting
@@ -1395,7 +1437,7 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # self-contained prompt, then tells the human where to paste it.
           learn() {
             (cd "$PIPULATE_ROOT" && python prompt_foo.py \
-              "You are Yen Sid-ton, the onboarding wizard for Pipulate. A newcomer wants to install Pipulate for the first time. Your FIRST reply must be short and do four things in order: (1) confirm in one line that you hold the full install map (installer, flake, both Pipulate.com pages); (2) show the one-line install command immediately, since it is identical on every OS; (3) ask exactly one question, which OS they are on, noting it changes only the caveats, never the command; (4) add one line noting the command assumes Nix is already installed, and that a nix command not found response means install Nix first and reopen the terminal. From then on: one step per turn, one question maximum per turn, and every step ends with a visible success checkpoint describing what they should literally see (the figlet banner, the JupyterLab URL, the spoken voice greeting) plus the single most likely failure symptom at that step and its fix. Deliver the macOS --impure exception and the reopen-your-terminal-after-installing-Nix requirement at the moment each can bite, never as an upfront lecture. Offer the magic cookie internals (ZIP + ROT13 key, then git transformation and auto-updates inside nix develop) as an optional aside when relevant or when asked, not as mandatory explanation. When both the server and JupyterLab are confirmed running, declare the install banked and teach the re-entry incantation: cd into the install folder, then nix develop. High signal, low noise. Ask them what they see; never assume." \
+              "You are Yen Sid-ton, the onboarding wizard for Pipulate. A newcomer wants to install Pipulate for the first time. Your FIRST reply must be short and do four things in order: (1) confirm in one line that you hold the full install map (installer, flake, both Pipulate.com pages); (2) show the one-line install command immediately, since it is identical on every OS; (3) ask exactly one question, which OS they are on, noting it changes only the caveats, never the command; (4) add one line noting the command assumes Nix is already installed, and that a nix command not found response means install Nix first and reopen the terminal. From then on: one step per turn, one question maximum per turn, and every step ends with a visible success checkpoint describing what they should literally see (the one-line environment readings, the two-door menu where they press 1, the figlet banner once the app starts, the JupyterLab URL, the spoken voice greeting) plus the single most likely failure symptom at that step and its fix. Deliver the macOS --impure exception and the reopen-your-terminal-after-installing-Nix requirement at the moment each can bite, never as an upfront lecture. Offer the magic cookie internals (ZIP + ROT13 key, then git transformation and auto-updates inside nix develop) as an optional aside when relevant or when asked, not as mandatory explanation. When both the server and JupyterLab are confirmed running, declare the install banked and teach the re-entry incantation: cd into the install folder, then nix develop. High signal, low noise. Ask them what they see; never assume." \
               --chop INSTALL_CHOP --no-tree)
             echo ""
             echo "🧞 The First Wish is compiled and sitting in your clipboard."
diff --git a/scripts/boot_menu.py b/scripts/boot_menu.py
index 33046ab7..586854fc 100644
--- a/scripts/boot_menu.py
+++ b/scripts/boot_menu.py
@@ -182,10 +182,10 @@ def main() -> int:
     if choice == EXIT_SHELL:
         print(f"Staying in the shell. Nothing started -- no {name}, no JupyterLab.")
         print()
-        print("Three words get you everywhere:")
+        print("Three words to start from:")
+        print("  sources   see what this shell can reach outside this machine")
         print("  learn     hand this whole workshop to an AI in a web chat")
-        print("  sources   see what reaches outside this machine")
-        print(f"  pu        start {name} (long form: pipulate)")
+        print(f"  pu        change your mind and start {name} after all")
     else:
         print(f"Starting {name}...")
     return choice
(nix) pipulate $ m
📝 Committing: chore: Move figlet banner to door 1
[main 1d620ee2] chore: Move figlet banner to door 1
 2 files changed, 48 insertions(+), 6 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Delta compression using up to 48 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 2.33 KiB | 1.17 MiB/s, done.
Total 8 (delta 6), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (6/6), completed with 5 local objects.
To github.com:pipulate/pipulate.git
   64bf563c..1d620ee2  main -> main
(nix) pipulate $ exit
exit
(sys) pipulate $ ndq
(nix) pipulate $ 
```

Oh whoops, I need to do this:

```bash
(nix) pipulate $ exit
exit
(sys) pipulate $ nix develop
warning: Git tree '/home/mike/repos/pipulate' is dirty
Checking for updates...
⚠️  Local modifications detected. Skipping automatic update to protect your work.
   Commit, stash, or revert them, then re-enter nix develop to update.
nix (Nix) 2.25.0pre20240910_b9d3cdfb · Python 3.12.13 · v2.44 · /home/mike/repos/pipulate
╭────────────────────────────────────────────────── Pipulate :: pick a door ──────────────────────────────────────────────────╮
│                                                                                                                             │
│  [1]  Start Pipulate   JupyterLab + server + browser tabs                                                                   │
│  [2]  Just the shell   nothing starts -- type  learn  for the guided tour                                                   │
│                                                                                                                             │
╰───────────────────────────────── waiting for your choice -- Ctrl+C also drops to the shell ─────────────────────────────────╯

Staying in the shell. Nothing started -- no Pipulate, no JupyterLab.

Three words to start from:
  sources   see what this shell can reach outside this machine
  learn     hand this whole workshop to an AI in a web chat
  pu        change your mind and start Pipulate after all
(nix) pipulate $
```

**4: Prompt**: The identity car landed. Ignition was `exit` then `nix develop`, and I pressed both doors. Probes 1-3 are real AFTERs; probe 4 is a field preview whose before and after are expected to be identical.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each:
- Probe 1: five lines is the pass -- three NIX_READING hits where the banner was, and figlet plus echo "Version: displaced BELOW the BOOT_CHOICE gate. Give me the line numbers and say which direction each moved. Two lines means nothing landed; four means one block failed and I want to know which.
- Probe 2: `get you everywhere` must be gone and `two-door menu` and `to start from` must both be present. If all three are silent that is evidence about my patterns before it is evidence about the files, and say which you concluded.
- Probe 3: eval_exit=0 proves versionNumber is in scope. Compare the drv hash to nothing -- I have no BEFORE for it -- so rule only on the exit code and say so plainly rather than reading a hash you cannot compare.
- Probe 4: quote the rendered line and its char count back to me. Under 80 is the pass. If it is over, name by how much and which field to cut.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Here is what I saw with my own eyes on re-entry, which no probe can witness:

[paste the door-2 output here, and the door-1 output here]

Then the next discrete step, and only that one: the vocabulary car. `learn` fails the mechanical test -- nobody learns, a payload compiles and a clipboard fills -- and what a newcomer actually sees is the Rich Payload Ledger and the console summary, which is a token-budget accounting table answering "teach me."

1. The word. Give me your one pick with the reason, not a list. It has to work as a verb a stranger types at a prompt.
2. Whether the fix is the rename, the --quiet on prompt_foo.py that gates step 5 only, or both in one car -- and if both, say why they are one story rather than two.
3. If --quiet is in scope, the exact boundary: name every line that must stay loud and which step prints it, so I can see that the secrets tripwire and the disclosure receipt are structurally out of reach of the flag.
4. The complete same-car label sweep, including yesterday's published article if the word changes.
5. Say explicitly what that car does NOT touch.

Hold the mcp roster row, the connectors/README.md "Current connectors" list, and the earmark item 1 Corporate correction for their own cars. Do not bundle them here.

**5: Deliverables**: Getting closer.

**Opus 5 Max**: Context verified.

## The ruling — three passes, one fail, and one thing your own instruction under-claimed

All four echoed lines are in the Manifest's LIVE COMMAND RECEIPTS, so every ruling below is a real AFTER from the compile lane.

**Probe 1 — PASS, five lines, and the displacement reads clean in both directions.** `NIX_READING` at 648/649/652, `figlet` at 750, `echo "Version:` at 751. Your hand-run BEFORE had figlet/Version at 620/621 and zero `NIX_READING`. So the banner moved **down** 130 lines and the readings landed **at** the banner's former position (the block opens at 620; 28 comment lines put the first executable line at 648, which is the arithmetic the patch predicts exactly). Raw source in this payload independently confirms the ordering — `figlet` sits after the `exit 0` inside the `BOOT_CHOICE -eq 10` branch. One caveat I will not paper over: I have **no AFTER line number for the gate itself**, because this probe never grepped `BOOT_CHOICE`. The ordering is read off raw source, not off a receipt.

**Probe 2 — PASS, all three conditions.** `get you everywhere` gone. `to start from` present at `boot_menu.py:185`. `two-door menu` present at `flake.nix:1440`, inside the Yen Sid-ton prompt. Not silent on all three, so no question about my patterns arises.

**Probe 3 — PASS on the exit code, and you *do* have a BEFORE.** `eval_exit=0`, so `${versionNumber}` is in scope and the `default` devShell evaluates. But your prompt said "I have no BEFORE for it," and that is not right — your own hand-run block at the top of this turn printed `fr5kx4qdbawafg13zm4widda3bzg8g46`, and this compile printed `4bzyr2m8b63zy4sa53jrawxqzd29xl5s`. Clean tree, probes first, patches second: that hand-run **is** the BEFORE tap. **The drv hash changed**, which is the ignition witness I claimed it would be — the patched `runScript` text is what a fresh `nix develop` instantiates.

One confound, named rather than waved off: the AFTER carries `warning: Git tree is dirty` (the compiler's own paintbox rewrite of `foo_files.py`). A `mkShell` derivation takes its packages and its `shellHook` string as inputs, not the source tree, so `foo_files.py` churn is not a plausible cause of the hash move — but I cannot prove that from a receipt, and I do not need to, because probe 1 already proves the text landed. Treat the hash change as corroboration, not load-bearing.

**Probe 4 — FAIL. 89 chars, over by 9.**

```text
nix (Nix) 2.25.0pre20240910_b9d3cdfb · Python 3.12.13 · v2.44 · /home/mike/repos/pipulate
```

Field-by-field: nix 36, ` · ` 3, Python 14, ` · ` 3, version 5, ` · ` 3, path 25 = 89. And it agrees byte-for-byte with the line in your pasted door-2 output, so the preview and the live render match — two lanes, one string.

**Which field to cut, and the ordering principle:** cut redundancy before cutting readings, and bound the *unbounded* field first.

1. **The path is the only field that can grow without bound.** 25 here; `~/Documents/code/pipulate` on a stranger's Mac pushes the same line past 100. Tilde-shortening saves 9 *and* bounds it structurally.
2. **The `nix ` prefix is pure redundancy**, not a reading — the parenthetical right after it is the discriminator (`(Nix)` vs `(Determinate Nix 3.x)`). Saves 4.

Together: **76**, with headroom, and nothing that is a reading gets destroyed. Truncating the prerelease build string is explicitly off the table — that is the LAST-INCH failure this whole thread has been convicting.

**One softening, in your favour:** this is a `printf`, not a Rich panel. At 80 columns it *soft-wraps* — every field survives on a second line. The `warm` row two rides ago was hard-wrapped inside a box border and produced an orphaned `│  wallet.  │`. So this is a cosmetic fail, not a structural one, and Car A below is genuinely vetoable.

**Incidentally, the discrimination is working.** Your box reports `nix (Nix) 2.25.0pre...` — **generic Nix**, not Determinate. A boolean would have said `True` and told you nothing.

---

## Two things that fit no branch

**Door 1 was never witnessed.** Your paste shows the re-entry and door 2 only; the `[paste the door-1 output here]` slot came back empty. So the figlet's new home has been read by `rg` and by raw source and by **no human eye**. That is REFUSAL-ONLY WITNESS in mirror form: we have seen the path where the banner does not print, never the path where it does. Cost to close it is a full startup plus Ctrl+C — named below, your call.

**The sweep list I gave you last turn was incomplete, and your own paste is the receipt.** The panel in your door-2 output reads:

> `[2]  Just the shell   nothing starts -- type  learn  for the guided tour`

That string lives in `boot_menu.py`'s `_render`, it is the line a human reads **before choosing a door**, and it has never appeared in any sweep list I have written. It advertises `learn` *and* calls the result a "guided tour," which is the same false promise twice on the highest-traffic surface there is.

---

## The vocabulary car

### 1. The word: `brief`

One pick, and the reason has to survive the obvious objection, so here is the objection first: typed bare, `brief` reads as *"brief me"*, and the command does not brief you — it briefs an AI.

That objection is real and it is survivable, because the two failures are not the same size. `brief` names an **artifact the command actually produces**; the only thing under-specified is the recipient, and the card's own line supplies it in six words. `learn` names an **act no code in the pipeline performs, ever** — nothing teaches anyone anything, and no card copy repairs that. The mechanical test's boundary sits exactly there: a word that names a real output with an implied recipient passes; a word that names a fictional act does not.

Everything else falls out: five characters, aligns with `sources` and `pu` in the card, a real English verb a stranger will not hesitate over, no builtin to shadow, and it sits naturally beside `seed` — both produce a document you hand to someone.

Runner-up was `handoff` (unambiguous about direction, but seven characters and a compound noun being verbed). Rejected `ask` and `explain` outright: both promise inline answering, and there *is* a local model in this system, so they would be false in the most expensive way.

**One pre-flight I cannot run for you and am deliberately not putting in the probe block:** type `command -v brief` at your prompt before applying Car C. A collision from your `~/repos/nixos/packages.nix` is the one candidate this compile cannot see, and a `!` echo of that check is a ritual — it prints not-found in the compile lane whether or not a collision exists, because functions and aliases do not inherit.

### 2. Rename, `--quiet`, or both — one story, two cars

**Both, and they are one story.** The rename fixes the *word's* promise; `--quiet` fixes the *output's*. Ship the rename alone and a stranger types `brief` and receives a token-budget accounting table — the word becomes honest and the experience stays wrong, and you have written a label describing an output nobody would call a briefing. That is the SAME-CAR LABEL failure with the output itself as the label.

**Two cars, not one**, per your own PATCH CAR BUNDLING note: a car is one *commit story*, and these teach different lessons — "rename the handoff command and every label that names it" versus "give the compiler a flag that suppresses its accounting." Different blast radii too: the flag touches the compiler every other alias shares.

**Order matters and I have arranged it so it does not.** Car B adds the flag *and* wires it into `learn()` while `learn()` still exists, so B is complete on its own. Car C then renames and never touches the chop line. Either order works; if you veto one, nothing breaks.

### 3. The `--quiet` boundary — one line, read once

The flag's entire reach is a single conjunct:

```python
if "Summary" in builder.all_sections and not args.quiet:
```

`args.quiet` is read **exactly once, on that line**, and that line gates one `if` whose body is the whole of step 5 — the Payload Ledger and the console summary, both. Nothing else in `main()` ever reads it. That is a structural argument, not a promise.

Everything that must stay loud, with the step that prints it — every one of these lives at `main()`'s module indentation *after* that block, or inside a function called after it:

| line | step |
|---|---|
| `🪄 Compile-lane scrub: N PII substitution(s)` | 6 |
| `🧼 PII rewrite: Nx 'pattern' -> 'repl'` | 6 (inside `scrub_compile_payload`) |
| `🔎 Render canary: N bare www-token(s)` | 6 |
| `🔐 Secrets tripwire: ARMED — N hit(s)` | 6, unconditional |
| `🛑 PAYLOAD BLOCKED` + `sys.exit(1)` | 6 |
| `🔓 DISCLOSURE: profile=…` | 6 |
| `📦 Canonical context cartridge written…` | 7 |
| `🗂️ Rotated cartridge snapshot…` | 7 |
| `Markdown output copied to clipboard` | 8 |

**And what it does *not* silence, which you should know before you ship it.** Steps 1–4 print through `logger.print` long before the gate: `📊 Stats block refreshed`, `🗺️ Codex Mapping Coverage`, `📦 Appending N uncategorized files`, `✅ Topological Integrity Verified`, `--- Processing Files ---`, the Ruff block. Call it six to eight surviving lines. `--quiet` removes the bulk — the table — and leaves compiler-maintenance chatter that a first-contact reader still should not see. Silencing *that* is a different decision touching a different mechanism, and it is not in this car.

### 4. The same-car label sweep

**Complete for the four files in this payload** — `flake.nix`, `boot_menu.py`, `sources_menu.py`, `foo_files.py` — and every one of them is patched below.

**A floor, not a census, for the corpus.** Not in this compile and therefore unswept: `README.md`, `AGENTS.md`, `assets/installer/install.sh`, `AI_CONTEXT.md` (generated — downstream of whatever it names), `assets/scenarios/*.json`, `apps/050_documentation.py`. Probe 1 sizes all of those and pairs its capped list with an uncapped count so the cap can never hide the total.

**Outside this repo entirely, and outside probe 1's reach:** `~/repos/Pipulate.com/{index,install,guide}.md`, and yesterday's published article. Whether `2026-08-24-paste-what-you-have-composable-text-commands.md` names `learn` at all, I do not know and will not guess — `rgxc learn` in that corpus settles it in one keystroke.

**No compatibility alias.** Two words for one job is the sibling-`.md` failure with our own hands on it, and `command not found` is a loud wound rather than a quiet lie. The in-terminal path stays self-consistent because the card the stranger just read says `brief`; only external docs can strand, and they strand noisily.

### 5. What the vocabulary car does NOT touch

- **`seed`** — the distributable twin. Same mechanism, different audience; renaming it is a separate decision.
- **"The First Wish"** — the *artifact's* handle stays. `brief` names the command; the genie echo is untouched, so the seed lane's vocabulary does not move.
- **The Yen Sid-ton prompt text** — just edited for the two-door menu. Persona and instructions unchanged.
- **`sources`, `tools`, `mcp`, `pu`** — settled last car.
- **`help`** — you floated it, and it is a third word plus a deliberate builtin shadow. Its own car.
- **Steps 1–4 console chatter, and every step-6/7/8 gate** — structurally out of `--quiet`'s reach.
- **The readings-line width** — Car A, separable, vetoable.
- **The `mcp` roster row, `connectors/README.md`'s "Current connectors" list, earmark item 1's `Corporate/` staleness** — held, as instructed.

---

## 1. PROBES

```bash
rg -c --hidden -g '!.git' -w learn | sort -t: -k2 -rn | head -20; rg -l --hidden -g '!.git' -w learn | wc -l
rg -n --hidden -g '!.git' -w -e learn -e brief flake.nix scripts/boot_menu.py scripts/sources_menu.py
rg -n -e 'args\.quiet' -e 'Secrets tripwire' -e 'DISCLOSURE:' prompt_foo.py; rg -n -- '--quiet' flake.nix
rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
```

Probe 1 sizes the sweep I cannot see, and the trailing `wc -l` is the fix for THE CAP THAT HID THE ANSWER — the capped list can never hide the true file count. Probe 2 is the discriminator for Car C: BEFORE is several `learn` and zero `brief` across the three shell-surface files, AFTER is the exact mirror. Probe 3 witnesses Car B in both halves and proves the boundary positionally — `args.quiet` must appear exactly once, at a **lower** line number than every tripwire and disclosure hit, which is the structural claim in §3 rendered as a receipt. Probe 4 is Car A's straddle: three `NIX_READING` hits before, five lines after with two `PWD_READING`.

I have deliberately **not** echoed a `prompt_foo.py --quiet` smoke test. The OUROBOROS LOCK fires on any nested compile, so its compile-lane AFTER would be the lock receipt — informative about the fence, silent about the flag.

## 2. NEXT CONTEXT

```text
! rg -c --hidden -g '!.git' -w learn | sort -t: -k2 -rn | head -20; rg -l --hidden -g '!.git' -w learn | wc -l
! rg -n --hidden -g '!.git' -w -e learn -e brief flake.nix scripts/boot_menu.py scripts/sources_menu.py
! rg -n -e 'args\.quiet' -e 'Secrets tripwire' -e 'DISCLOSURE:' prompt_foo.py; rg -n -- '--quiet' flake.nix
! rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
flake.nix
scripts/boot_menu.py
scripts/sources_menu.py
prompt_foo.py
foo_files.py
apply.py
```

**Drop ballast — this ran 267k and the next car touches five files.** Safe to comment out for one turn: `GLOSSARY.md`, `~/repos/nixos/autognome.py`, `init.lua`, `release.py`, `cli.py`, `scripts/xp.py`, `scripts/ai.py`, `scripts/foo_cartridge.py`, `scripts/foo_replay.py`, `scripts/weblogin.py`, `scripts/crawl.py`, `requirements.in`, `pyproject.toml`, `__init__.py`, `.gitattributes`, `.gitignore`. Roughly 60k.

## 3. PATCHES

**Car A — the identity car's own width debt.** One block. Veto costs nothing: the line still prints every field, it merely soft-wraps at 80.

```text
Target: flake.nix
[[[SEARCH]]]
          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1)
          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
          PY_READING=$(python -V 2>&1)
          if [ -z "$PY_READING" ]; then PY_READING="python: no reading"; fi
          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD"
[[[DIVIDER]]]
          # 89 CHARS ON ITS FIRST FLIGHT, MEASURED (2026-08-25). Two cuts, in
          # the order that matters: BOUND THE UNBOUNDED FIELD FIRST, then
          # remove redundancy, and never truncate a reading.
          #   $PWD is the only field that can grow without limit -- 25 here,
          #     but ~/Documents/code/pipulate on a stranger's Mac pushes this
          #     line past 100. Tilde-shortening saves 9 AND bounds it.
          #   The leading "nix " is redundant with the parenthetical that
          #     follows it, and the parenthetical is the whole discriminator:
          #     "(Nix) 2.25.0..." is generic, "(Determinate Nix 3.x) 2.x" is
          #     DetSys. Saves 4 and destroys nothing.
          # 89 - 9 - 4 = 76, with headroom. Truncating the prerelease build
          # string was REFUSED: that is the LAST-INCH failure -- a correct
          # reading destroyed by the transformation nearest the reader.
          # NO ${ ANYWHERE BUT THE NIX ONE: this is a Nix indented string, so
          # bash parameter expansion would be eaten by the interpolator. sed
          # does the work instead; ''${versionNumber} stays Nix's on purpose.
          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1 | sed 's/^nix //')
          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
          PY_READING=$(python -V 2>&1)
          if [ -z "$PY_READING" ]; then PY_READING="python: no reading"; fi
          PWD_READING=$(printf '%s' "$PWD" | sed "s|^$HOME|~|")
          if [ -z "$PWD_READING" ]; then PWD_READING="$PWD"; fi
          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD_READING"
[[[REPLACE]]]
```

**Car B — the flag.** Complete on its own: `learn` still exists and starts using it immediately.

```text
Target: prompt_foo.py
[[[SEARCH]]]
    parser.add_argument('-n', '--no-tree', action='store_true', help='Suppress file tree and UML generation.')
[[[DIVIDER]]]
    parser.add_argument('-n', '--no-tree', action='store_true', help='Suppress file tree and UML generation.')
    # THE ACCOUNTING GOES QUIET; THE GATES DO NOT (2026-08-25). At minute zero
    # of first contact, the onboarding command's answer to "teach me" was a
    # token-budget table -- the machinery showing through at exactly the moment
    # the Stick Bug is supposed to be invisible. This flag is read EXACTLY ONCE,
    # on the step-5 conjunct below, and gates ONE if. The step-6 sanitizer,
    # secrets tripwire, render canary and disclosure receipt, and the step-7
    # cartridge write, all sit AFTER that block at main()'s own indentation and
    # are therefore STRUCTURALLY unreachable from here -- silencing any of them
    # would recreate THE SILENT-PASS PROBLEM, where an armed gate and a
    # disarmed gate print identically. It does not reach steps 1-4 either:
    # the paintbox, integrity and processing lines print through logger.print
    # long before this. Bulk removed, receipts intact.
    parser.add_argument('--quiet', action='store_true', help='Suppress the step-5 console echo (Payload Ledger + Summary). Cannot reach the step-6 sanitizer, secrets tripwire, render canary, or disclosure receipt.')
[[[REPLACE]]]
Target: prompt_foo.py
[[[SEARCH]]]
    # 5. Print the Summary section to console for immediate feedback
    if "Summary" in builder.all_sections:
        console_summary = builder.all_sections["Summary"]["content"]
[[[DIVIDER]]]
    # 5. Print the Summary section to console for immediate feedback
    # THE FLAG'S ENTIRE REACH IS THIS CONJUNCT. args.quiet is read here and
    # nowhere else in this file, and the body of this if is the whole of step
    # 5 -- ledger and summary both. See the --quiet argparse comment above.
    if "Summary" in builder.all_sections and not args.quiet:
        console_summary = builder.all_sections["Summary"]["content"]
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
              --chop INSTALL_CHOP --no-tree)
[[[DIVIDER]]]
              --chop INSTALL_CHOP --no-tree --quiet)
[[[REPLACE]]]
```

**Car C — the word.** One commit story across four files.

```text
Target: flake.nix
[[[SEARCH]]]
          # THE FIRST WISH: `learn` is to Pipulate what vimtutor is to vim.
          # (Resurrects the dead V7 Unix `learn` CAI tutor name — no modern collision.)
          # Compiles the INSTALL_CHOP onboarding context into the clipboard with a
          # self-contained prompt, then tells the human where to paste it.
          learn() {
[[[DIVIDER]]]
          # THE FIRST WISH, RENAMED (2026-08-25). `learn` failed the
          # ATTRIBUTED-VOICE mechanical test: it named an act no code in this
          # pipeline performs. Nobody learns anything -- a payload compiles and
          # a clipboard fills. `brief` names an artifact the command ACTUALLY
          # PRODUCES, which is the whole difference. The obvious objection --
          # that "brief" read bare sounds like "brief me" -- is survivable and
          # `learn` was not: the recipient is under-specified by one word and
          # the card supplies it, whereas "teach me" is wholly false and no
          # card copy repairs it.
          # THE ARTIFACT KEEPS ITS NAME. The command is `brief`; the thing it
          # produces is still The First Wish, which is what INSTALL_CHOP and
          # the seed lane call it. Renaming the artifact too would drag `seed`
          # and SEED_PROMPT into a car that has no business touching them.
          # NO COMPATIBILITY ALIAS: two words for one job is the sibling-.md
          # failure, and `command not found` is a loud wound, not a quiet lie.
          # Compiles the INSTALL_CHOP onboarding context into the clipboard with a
          # self-contained prompt, then tells the human where to paste it.
          brief() {
[[[REPLACE]]]
Target: scripts/boot_menu.py
[[[SEARCH]]]
        "[2]  Just the shell   nothing starts -- type  learn  for the guided tour",
[[[DIVIDER]]]
        "[2]  Just the shell   nothing starts -- three words wait at the prompt",
[[[REPLACE]]]
Target: scripts/boot_menu.py
[[[SEARCH]]]
        print("  learn     hand this whole workshop to an AI in a web chat")
[[[DIVIDER]]]
        print("  brief     compile this workshop into your clipboard for an AI")
[[[REPLACE]]]
Target: scripts/sources_menu.py
[[[SEARCH]]]
    "Type  learn  to hand this whole workshop to an AI in a web chat.",
[[[DIVIDER]]]
    "Type  brief  to compile this workshop into your clipboard for an AI.",
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
# 8. For a full list of content distillation options, just type "learn".
[[[DIVIDER]]]
# 8. To hand this whole workshop to an AI in a web chat, type "brief".
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
# ALIAS: `learn` (flake.nix) — compiles this chop with a built-in onboarding
# prompt, fills the clipboard, and prints the paste-into-AI-WebChat steps.
[[[DIVIDER]]]
# ALIAS: `brief` (flake.nix) — compiles this chop with a built-in onboarding
# prompt, fills the clipboard, and prints the paste-into-AI-WebChat steps.
# Renamed from `learn` on 2026-08-25: nobody learns anything here, a payload
# compiles and a clipboard fills, and the word now names the artifact.
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
# Resolves learn()'s chicken-and-egg: `learn` requires the environment; this
[[[DIVIDER]]]
# Resolves brief()'s chicken-and-egg: `brief` requires the environment; this
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
#      homepage, the `learn` LLM payload, Honeybot station-identification
[[[DIVIDER]]]
#      homepage, the `brief` LLM payload, Honeybot station-identification
[[[REPLACE]]]
Target: foo_files.py
[[[SEARCH]]]
Bank into the learn()/seed() prompt copy in flake.nix.
[[[DIVIDER]]]
Bank into the brief()/seed() prompt copy in flake.nix.
[[[REPLACE]]]
```

## Aligning Artifact Names with Mechanical Reality

**IGNITION IS REQUIRED, and it splits per surface.** `prompt_foo.py`, `boot_menu.py`, `sources_menu.py` and `foo_files.py` self-ignite — each is read from disk at call time, so probes 1–3 are real AFTERs without re-entry. `flake.nix`'s `brief()` and the readings line live in the shellHook, read once at entry: **`exit`, then `nix develop`, then press 2.** Probe 4 reads source and does not need it.

If you want the figlet's new home witnessed by human eyes rather than by `rg` alone, that costs a second re-entry with **1** and a Ctrl+C out of the server. Optional, and I would rather you skip it than have it read as a receipt if you don't.

Choreography: `patch`, `app`, `d`, `m` (Car A) → `patch`, `app`, `d`, `m` (Car B) → `patch`, `app`, `d`, `m` (Car C) → `blast` → `exit`, `nix develop`, `2`.

## 4. PROMPT

```text
The vocabulary car landed. Ignition was `exit` then `nix develop` then door 2. The four Python-and-router files self-ignite; only flake.nix needed it.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each:
- Probe 1: give me the file count from the trailing wc -l first, then the list. If the head-20 list has exactly 20 lines, say TRUNCATED and rule from the count, not the list. Split the files into (a) surfaces a human or model reads at a decision point, which owe a sweep car, and (b) prose that merely mentions the word. Name any file you cannot confidently place.
- Probe 2: zero `learn` and several `brief` across the three shell-surface files is the pass. Any surviving `learn` there is a miss inside a car I claimed was complete for those files -- name the file and line.
- Probe 3: `args.quiet` must appear exactly once in prompt_foo.py and at a LOWER line number than every Secrets tripwire and DISCLOSURE hit. Give me the numbers. Two `args.quiet` hits means the flag leaked past its one conjunct and I want to know where. Then confirm flake.nix carries --quiet exactly once.
- Probe 4: five lines with two PWD_READING is the pass for Car A. Three lines means Car A was vetoed or did not land; say which you can tell from the receipt and which you cannot.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Here is what I saw on re-entry, which no probe can witness:
[paste the door-2 output here]

Then the next discrete step, and only that one: the residual sweep car, sized off probe 1.

1. The complete list of in-repo surfaces still naming `learn`, as SEARCH/REPLACE blocks against raw source actually present in the next context. If a file is not in that context, do not patch it -- name it and say what to add to adhoc.txt instead.
2. Which surfaces live OUTSIDE this repo and therefore ride Car 5 as carried text: Pipulate.com pages, yesterday's published article, anything else. For each, say what you need in context before you can carry it, since CARRIED-NOT-CITED means you cannot hand me a bibliography.
3. Whether AI_CONTEXT.md needs anything at all, given it is regenerated on every release.
4. Say explicitly what that car does NOT touch.

Hold the mcp roster row, the connectors/README.md "Current connectors" list, earmark item 1's Corporate staleness, `help` as a fourth word, and the steps 1-4 console chatter for their own cars. Do not bundle them here.
```

## 5. EXTERNAL DELIVERABLES

None this turn. The Pipulate.com pages and yesterday's article may both need the `learn` → `brief` edit, but CARRIED-NOT-CITED means I cannot hand you a deliverable for a file I have not read — `rgxc learn` and one `~/repos/Pipulate.com` line in the next chop close that.

**MikeLev.in**: 

**1: Probe**:

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

nothing to commit, working tree clean
(nix) pipulate $ rg -c --hidden -g '!.git' -w learn | sort -t: -k2 -rn | head -20; rg -l --hidden -g '!.git' -w learn | wc -l
rg -n --hidden -g '!.git' -w -e learn -e brief flake.nix scripts/boot_menu.py scripts/sources_menu.py
rg -n -e 'args\.quiet' -e 'Secrets tripwire' -e 'DISCLOSURE:' prompt_foo.py; rg -n -- '--quiet' flake.nix
rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
foo_files.py:7
requirements.txt:6
flake.nix:4
scripts/boot_menu.py:3
imports/ascii_displays.py:2
AI_RUNME.py:2
server.py:1
scripts/sources_menu.py:1
scripts/gsc/gsc_category_analysis.py:1
scripts/botify/make_botify_docs.ipynb:1
scripts/botify/botify_api_bootcamp.md:1
requirements.in:1
remotes/honeybot/scripts/stream.py:1
README.md:1
pyproject.toml:1
Notebooks/.agents/skills/roles/SKILL.md:1
assets/nbs/Onboarding.ipynb:1
assets/nbs/Educational_Notebooks/Truth_Actually.ipynb:1
18
scripts/sources_menu.py
90:    "Type  learn  to hand this whole workshop to an AI in a web chat.",

scripts/boot_menu.py
7:  [2] Just the shell    NOTHING starts; `learn`, `seed`, `foo`, `ahc` live here
88:        "[2]  Just the shell   nothing starts -- type  learn  for the guided tour",
187:        print("  learn     hand this whole workshop to an AI in a web chat")

flake.nix
1105:            printf "%s\n" "# Shared" "" "This is the one folder you use on purpose to hand work to someone else." "Everything else under Notebooks/ is either yours alone or delivered to you." "Nothing here is private: assume a teammate will read it." "" "Make a folder with your own name, and work inside it:" "" "    mkdir -p Notebooks/Shared/yourname" "" "One folder per person means two people can drop work at the same moment and" "never collide, so there is nothing to merge and no git to learn." "" "Pipulate git ignores this whole folder. To back yours up, put your own git" "repository inside your own subfolder; it will not fight with anything above." > "$PIPULATE_ROOT/Notebooks/Shared/README.md"
1434:          # THE FIRST WISH: `learn` is to Pipulate what vimtutor is to vim.
1435:          # (Resurrects the dead V7 Unix `learn` CAI tutor name — no modern collision.)
1438:          learn() {
3282:    # Secrets tripwire: runs on every payload, under every profile. A
3301:    print(f"🔐 Secrets tripwire: ARMED — {len(secret_hits)} hit(s) in payload.")
3337:        receipt = (f"🔓 DISCLOSURE: profile={profile_name} | "
663:          PIP_QUIET_FLAG="--quiet"
709:          git pull --quiet
844:          uv pip install -r requirements.txt --quiet
846:          uv pip install -e . --no-deps --quiet
936:            if ! git diff-index --quiet HEAD -- . ':!.jupyter/lab/user-settings'; then
946:              git stash push --quiet --include-untracked --message "Auto-stash JupyterLab settings" -- .jupyter/lab/user-settings/ 2>/dev/null || true
972:                if ! git stash apply --quiet "$PIPULATE_STASH" 2>/dev/null; then
980:                    git stash drop --quiet "$PIPULATE_STASH_NAME" 2>/dev/null || true
648:          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1)
649:          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
652:          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD"
(nix) pipulate $
```

**2: Context**:

```text
# adhoc.txt    _   _   _ to set context____ _   _  ___  ____  _   <F5> Simpson Couch Gag Here (explain anything to the audience you feel needs it explained)
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  Stick bug stuff
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  
# Ad Hoc CHOP: The Not-Managed-by-Git Safe-for-Client-Data place  

# THE ROLLING PIN BOOK ORE SPINE / FODDER FOR THE BOOK
# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- The "Rolling Pin" that gives the 40K foot book-spine view of book-ore.
# GLOSSARY.md                 # <-- I think this glossary goes well with the book-ore spine to do world building.
# scripts/articles/lsa.py     # <-- Useful for refining commands like `posts`, critical to Second Brain concept.

# THE QUIRKY AMIGA-LOVING HUMAN
# ~/repos/nixos/autognome.py  # <-- Letting the AIs really understand my environment (The Brave Little Tailor punches above Their Weight Class proving the dunning-kruger effect the gate-keeper's (lower-case) lament.)
# init.lua                    # <-- Daily driver hot-keys that overlap with aliases in flake.nix

# THE HAND-CRANKED AGENTIC FRAMEWORK
prompt_foo.py               # <-- Prompt Fu compiler, makes the very README for AGENTS-like payload you're reading right now, but it needs to be more like that
foo_files.py                # <-- This is the router, evolving book outline and the things you pin-up to produced the recursive self-improvement loops

# MAIN ACTUATORS, IaC & NEGATIVE SPACE
flake.nix                   # <-- Solves world's WRITE ONCE RUN ANYWHERE problem like Java never could. Also resolves the bootstrap paradox.
apply.py                    # <-- How can "Web UI" ChatBots edit your code? With this Aider-inspired Player Piano patch applier.
# .gitattributes              # <-- Model: understand that `nbstripout` and `jupytext` are both in play. Just talk the human through .ipynb patches.
# .gitignore                  # <-- Creates "negative space" for sub-rep's to share parent environment and "snap" proprietary secret features into place.
# requirements.in             # <-- All known dependencies and (necessary) version pinning. WORA gotcha's exposed.
# __init__.py                 # <-- Master versioning
# pyproject.toml              # <-- The PyPI Packaging details
# 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.
 
# CONTEXT PORTABILITY SYSTEM
# scripts/foo_cartridge.py    # Needs description
# scripts/foo_replay.py       # Needs description
 
# # FREQUENTLY USEFUL TO HAVE IN CONTEXT
# release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
# scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
# scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.

# imports/voice_synthesis.py  # <-- The wand can talk to you
# 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.  ---

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

# server.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
  
# tools/scraper_tools.py
# tools/__init__.py
# tools/dom_tools.py
# tools/llm_optics.py
# scripts/walk.py

# assets/trails/first_context.yaml
# scripts/weblogin.py

# ! ls browser_cache/looking_at

# assets/installer/replay.sh
# scripts/mother_cat.py

# # `d`, `Shift`+`G`! I have to remember that.
# 
# ! { echo "== auth ruling witness =="; grep -c 'NOT distinct rides at the trail level' foo_files.py | sed 's/^/auth_ruling=/'; grep -c '^# assets/trails/' foo_files.py | sed 's/^/trail_lines=/'; }
# ! { echo "== botify guided captures =="; .venv/bin/python -c 'import glob,json; F=sorted(glob.glob("browser_cache/looking_at/app.botify.com/*/headers.json")); print("captures", len(F)); [print(json.dumps({"provenance": h.get("source_provenance"), "selection": h.get("header_selection"), "title_len": len(h.get("title") or ""), "login_marker": any(t in (h.get("final_url") or "").lower() for t in ("signin", "login", "sso"))})) for f in F for h in [json.load(open(f, encoding="utf-8"))]]'; }
# ! { echo "== non-ascii in url-bearing frontmatter, uncapped =="; .venv/bin/python -c 'import glob,os; P=sorted(glob.glob(os.path.expanduser("~/repos/trimnoir/_posts/*.md"))); print("scanned", len(P)); [print(ascii(os.path.basename(f)), ascii(l)) for f in P for l in open(f,encoding="utf-8").read().split(chr(10)) if l.startswith(("permalink:","canonical_url:")) and any(ord(c) > 127 for c in l)]'; }
# ! { echo "== router burden by region =="; .venv/bin/python -c 'p=open("foo_files.py",encoding="utf-8").read(); i=p.find("# " + "#todo #to-do"); j=p.find("XIX. THE PAINTBOX"); print("total_bytes", len(p)); print("earmark_bytes", (j-i) if 0 < i < j else "MARKER-MISS"); print("paintbox_bytes", (len(p)-j) if j > 0 else "MARKER-MISS")'; }
# foo_files.py
# GLOSSARY.md
# scripts/walk.py
# scripts/mother_cat.py
# scripts/walk_cartridge.py
# scripts/weblogin.py
# tools/scraper_tools.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py
# scripts/connectors/botify.py
# assets/trails/practice.yaml
# assets/trails/public_walk.yaml
# assets/trails/first_context.yaml
# # assets/trails/botify_pageworkers.yaml

# # --- PROBE ECHOES (verbatim from car 1) ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -30
# 
# # --- ACQUISITION: uncomment exactly ONE, chosen by the wc receipt ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 400
# 
# # --- THE JIRA LANE (deliberately leaner than this compile) ---
# scripts/connectors/README.md
# scripts/connectors/jira.py
# scripts/connectors/wallet.py
# init.lua
# flake.nix
# foo_files.py
# prompt_foo.py
# apply.py

# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,re,httpx; b=(os.getenv("JIRA_URL") or re.sub(r"/wiki/?$","",(os.getenv("CONFLUENCE_URL") or os.getenv("CONFLUENCE_BASE_URL") or "").rstrip("/"))).rstrip("/"); r=httpx.get(b+"/_edge/tenant_info",timeout=15); print("tenant_info",r.status_code,r.text[:160]); s=httpx.get(b+"/rest/api/3/serverInfo",timeout=15); print("serverInfo",s.status_code,(s.json().get("deploymentType") if s.status_code==200 else s.text[:80]))'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc

# ~/repos/nixos/autognome.py                 #  <-- More rare to have to include, but the true "top" of the muscle memory stack for day-to-day purposes
# ~/repos/nixos/configuration.nix            #  <-- "Global" IaC context (most of you won't have)
# ~/repos/nixos/blogs.nix
# ~/repos/nixos/packages.nix                 #  <-- Full disclosure on pre-flake IaC available apps.
# ~/repos/nixos/services.nix                 #  <-- Running Linux system services.
# ~/repos/nixos/ai-acceleration.nix          #  <-- Paid a lot for your hardware? We've got you covered.
# ~/repos/nixos/hardware-configuration.nix   #  <-- Automatically generated by Nix. The ultimate in IaC transparency.

# scripts/articles/common.py                   # <-- Self-explanatory
# scripts/articles/confluenceizer.py           # <-- Idempotent Jekyll-to-Confluence corporate wiki

# scripts/connectors/jira.py
# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,httpx; b=os.environ["JIRA_URL"].rstrip("/"); r=httpx.get(b+"/rest/api/3/myself",auth=httpx.BasicAuth(os.environ["JIRA_EMAIL"],os.environ["JIRA_TOKEN"]),headers={"Accept":"application/json"},timeout=15); print("myself_status="+str(r.status_code)); print("seraph="+str(r.headers.get("x-seraph-loginreason"))); print(r.text[:200])'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 30

# scripts/boot_menu.py  # [1,671 tokens | 6,636 bytes]
# scripts/mcp_menu.py
# assets/installer/mck.sh     # <-- THE LAUNCHER: curl -fsSL pipulate.com/mck.sh | bash
# assets/installer/install.sh   # The magic cookie: curl-distributed, git-free bootstrap

# ! COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
# ! .venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
# ! rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40

# scripts/mcp_menu.py
# scripts/boot_menu.py

! rg -c --hidden -g '!.git' -w learn | sort -t: -k2 -rn | head -20; rg -l --hidden -g '!.git' -w learn | wc -l
! rg -n --hidden -g '!.git' -w -e learn -e brief flake.nix scripts/boot_menu.py scripts/sources_menu.py
! rg -n -e 'args\.quiet' -e 'Secrets tripwire' -e 'DISCLOSURE:' prompt_foo.py; rg -n -- '--quiet' flake.nix
! rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
flake.nix
scripts/boot_menu.py
scripts/sources_menu.py
prompt_foo.py
foo_files.py
apply.py
```

**3: Patches**: 

```diff
(nix) pipulate $ ahe
(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
❌ Error: Patching 'flake.nix' aborted. Invalid Nix syntax:
   error: syntax error, unexpected ':', expecting '}'
       at /tmp/nix-shell.MOLvsl/tmp1wrwjtkv.nix:661:43:
          660|           # reading destroyed by the transformation nearest the reader.
          661|           # NO ${ ANYWHERE BUT THE NIX ONE: this is a Nix indented string, so
             |                                           ^
          662|           # bash parameter expansion would be eaten by the interpolator. sed
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'prompt_foo.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'prompt_foo.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index cd2fdaf6..2d007730 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1438,7 +1438,7 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           learn() {
             (cd "$PIPULATE_ROOT" && python prompt_foo.py \
               "You are Yen Sid-ton, the onboarding wizard for Pipulate. A newcomer wants to install Pipulate for the first time. Your FIRST reply must be short and do four things in order: (1) confirm in one line that you hold the full install map (installer, flake, both Pipulate.com pages); (2) show the one-line install command immediately, since it is identical on every OS; (3) ask exactly one question, which OS they are on, noting it changes only the caveats, never the command; (4) add one line noting the command assumes Nix is already installed, and that a nix command not found response means install Nix first and reopen the terminal. From then on: one step per turn, one question maximum per turn, and every step ends with a visible success checkpoint describing what they should literally see (the one-line environment readings, the two-door menu where they press 1, the figlet banner once the app starts, the JupyterLab URL, the spoken voice greeting) plus the single most likely failure symptom at that step and its fix. Deliver the macOS --impure exception and the reopen-your-terminal-after-installing-Nix requirement at the moment each can bite, never as an upfront lecture. Offer the magic cookie internals (ZIP + ROT13 key, then git transformation and auto-updates inside nix develop) as an optional aside when relevant or when asked, not as mandatory explanation. When both the server and JupyterLab are confirmed running, declare the install banked and teach the re-entry incantation: cd into the install folder, then nix develop. High signal, low noise. Ask them what they see; never assume." \
-              --chop INSTALL_CHOP --no-tree)
+              --chop INSTALL_CHOP --no-tree --quiet)
             echo ""
             echo "🧞 The First Wish is compiled and sitting in your clipboard."
             echo "   1. Open an AI web chat: Claude, ChatGPT, or Gemini."
diff --git a/prompt_foo.py b/prompt_foo.py
index 31c10e63..7596fe81 100644
--- a/prompt_foo.py
+++ b/prompt_foo.py
@@ -2380,6 +2380,19 @@ def main():
     parser.add_argument('--check-dependencies', action='store_true', help='Verify that all required external tools are installed.')
     parser.add_argument('--context-only', action='store_true', help='Generate a context-only prompt without file contents.')
     parser.add_argument('-n', '--no-tree', action='store_true', help='Suppress file tree and UML generation.')
+    # THE ACCOUNTING GOES QUIET; THE GATES DO NOT (2026-08-25). At minute zero
+    # of first contact, the onboarding command's answer to "teach me" was a
+    # token-budget table -- the machinery showing through at exactly the moment
+    # the Stick Bug is supposed to be invisible. This flag is read EXACTLY ONCE,
+    # on the step-5 conjunct below, and gates ONE if. The step-6 sanitizer,
+    # secrets tripwire, render canary and disclosure receipt, and the step-7
+    # cartridge write, all sit AFTER that block at main()'s own indentation and
+    # are therefore STRUCTURALLY unreachable from here -- silencing any of them
+    # would recreate THE SILENT-PASS PROBLEM, where an armed gate and a
+    # disarmed gate print identically. It does not reach steps 1-4 either:
+    # the paintbox, integrity and processing lines print through logger.print
+    # long before this. Bulk removed, receipts intact.
+    parser.add_argument('--quiet', action='store_true', help='Suppress the step-5 console echo (Payload Ledger + Summary). Cannot reach the step-6 sanitizer, secrets tripwire, render canary, or disclosure receipt.')
     parser.add_argument('--chop', type=str, default='AI_PHOOEY_CHOP', help='Specify an alternative payload variable from foo_files.py')
     parser.add_argument('--bumper', type=str, default=None, help='Inject a pre-registered bumper matrix from flippers.json (e.g., gold, cat)')
     parser.add_argument('--line-numbers', action='store_true', help='Prefix source lines with line numbers for review/navigation only. Do not use this mode for SEARCH/REPLACE patch generation.')
@@ -3138,7 +3151,10 @@ def main():
     final_output = builder.build_final_prompt()
 
     # 5. Print the Summary section to console for immediate feedback
-    if "Summary" in builder.all_sections:
+    # THE FLAG'S ENTIRE REACH IS THIS CONJUNCT. args.quiet is read here and
+    # nowhere else in this file, and the body of this if is the whole of step
+    # 5 -- ledger and summary both. See the --quiet argparse comment above.
+    if "Summary" in builder.all_sections and not args.quiet:
         console_summary = builder.all_sections["Summary"]["content"]
         
         # FIX: Strip the redundant Processing Log specifically for terminal display
(nix) pipulate $ m
📝 Committing: chore: Remove --quiet argument from prompt_foo.py
[main 125b14fe] chore: Remove --quiet argument from prompt_foo.py
 2 files changed, 18 insertions(+), 2 deletions(-)
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/boot_menu.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/boot_menu.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/sources_menu.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'foo_files.py'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index 2d007730..d13d5d08 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1431,11 +1431,24 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
             ahc
           }
           alias pins='(cd "$PIPULATE_ROOT" && python prompt_foo.py --chop PINNED_CHOP --no-tree)'
-          # THE FIRST WISH: `learn` is to Pipulate what vimtutor is to vim.
-          # (Resurrects the dead V7 Unix `learn` CAI tutor name — no modern collision.)
+          # THE FIRST WISH, RENAMED (2026-08-25). `learn` failed the
+          # ATTRIBUTED-VOICE mechanical test: it named an act no code in this
+          # pipeline performs. Nobody learns anything -- a payload compiles and
+          # a clipboard fills. `brief` names an artifact the command ACTUALLY
+          # PRODUCES, which is the whole difference. The obvious objection --
+          # that "brief" read bare sounds like "brief me" -- is survivable and
+          # `learn` was not: the recipient is under-specified by one word and
+          # the card supplies it, whereas "teach me" is wholly false and no
+          # card copy repairs it.
+          # THE ARTIFACT KEEPS ITS NAME. The command is `brief`; the thing it
+          # produces is still The First Wish, which is what INSTALL_CHOP and
+          # the seed lane call it. Renaming the artifact too would drag `seed`
+          # and SEED_PROMPT into a car that has no business touching them.
+          # NO COMPATIBILITY ALIAS: two words for one job is the sibling-.md
+          # failure, and `command not found` is a loud wound, not a quiet lie.
           # Compiles the INSTALL_CHOP onboarding context into the clipboard with a
           # self-contained prompt, then tells the human where to paste it.
-          learn() {
+          brief() {
             (cd "$PIPULATE_ROOT" && python prompt_foo.py \
               "You are Yen Sid-ton, the onboarding wizard for Pipulate. A newcomer wants to install Pipulate for the first time. Your FIRST reply must be short and do four things in order: (1) confirm in one line that you hold the full install map (installer, flake, both Pipulate.com pages); (2) show the one-line install command immediately, since it is identical on every OS; (3) ask exactly one question, which OS they are on, noting it changes only the caveats, never the command; (4) add one line noting the command assumes Nix is already installed, and that a nix command not found response means install Nix first and reopen the terminal. From then on: one step per turn, one question maximum per turn, and every step ends with a visible success checkpoint describing what they should literally see (the one-line environment readings, the two-door menu where they press 1, the figlet banner once the app starts, the JupyterLab URL, the spoken voice greeting) plus the single most likely failure symptom at that step and its fix. Deliver the macOS --impure exception and the reopen-your-terminal-after-installing-Nix requirement at the moment each can bite, never as an upfront lecture. Offer the magic cookie internals (ZIP + ROT13 key, then git transformation and auto-updates inside nix develop) as an optional aside when relevant or when asked, not as mandatory explanation. When both the server and JupyterLab are confirmed running, declare the install banked and teach the re-entry incantation: cd into the install folder, then nix develop. High signal, low noise. Ask them what they see; never assume." \
               --chop INSTALL_CHOP --no-tree --quiet)
diff --git a/foo_files.py b/foo_files.py
index c7445de9..a83a3014 100644
--- a/foo_files.py
+++ b/foo_files.py
@@ -32,7 +32,7 @@ AI_PHOOEY_CHOP = r"""#
 # 5. Type `foo` for simple compile or `fu` for file-tree and UML version.
 # 6. Paste in consumer-tier Web UI ChatBot frontier model of your choice.
 # 7. Enjoy the fun that ensues as whatever model helps you gain traction.
-# 8. For a full list of content distillation options, just type "learn".
+# 8. To hand this whole workshop to an AI in a web chat, type "brief".
 
 #               > There's something happening here.  
 #               > Just in case it's not entirely clear:  
@@ -2200,8 +2200,10 @@ pyproject.toml              # <-- The PyPI Packaging details
 INSTALL_CHOP = r"""
 # THE FIRST WISH (First-time install onboarding context)
 # COMMAND: python prompt_foo.py --chop INSTALL_CHOP --no-tree
-# ALIAS: `learn` (flake.nix) — compiles this chop with a built-in onboarding
+# ALIAS: `brief` (flake.nix) — compiles this chop with a built-in onboarding
 # prompt, fills the clipboard, and prints the paste-into-AI-WebChat steps.
+# Renamed from `learn` on 2026-08-25: nobody learns anything here, a payload
+# compiles and a clipboard fills, and the word now names the artifact.
 # Everything Yen Sid-ton needs to walk a newcomer from bare terminal to a
 # running Pipulate: the curl|bash bootstrap, the magic cookie hand-off, and
 # the flake that completes the git transformation. The one-liner:
@@ -2242,7 +2244,7 @@ expertise in what should happen next. Choose your 3 favorites and why."""
 SEED_CHOP = r"""
 # THE BOOK SEED (Distributable First Wish — compiled BY an owner, FOR a stranger)
 # COMMAND: python prompt_foo.py @SEED_PROMPT --chop SEED_CHOP --no-tree
-# Resolves learn()'s chicken-and-egg: `learn` requires the environment; this
+# Resolves brief()'s chicken-and-egg: `brief` requires the environment; this
 # artifact does not. An existing installer compiles once, then hands off the
 # newest rotated foo-<hash8>-NN.zip (verifiable receivers) or an
 # `-o first_wish.md` render (chatbots without code execution). The receiver
@@ -3115,7 +3117,7 @@ scripts/xp.py  # [672 tokens | 2,521 bytes]
 #      first, then `print(binascii.crc32(art.encode('utf-8')))`, then seal.
 #   6. ART DEPLOYMENT SURFACES (the REDUNDANT-GROOVE play made literal): once
 #      registered, the workspace-tree art renders into README.md / the GitHub
-#      homepage, the `learn` LLM payload, Honeybot station-identification
+#      homepage, the `brief` LLM payload, Honeybot station-identification
 #      breaks, and prompt_foo.py's own educational output. One master, many
 #      projections -- the handles-not-homes discipline the Jekyll lane already
 #      runs on prose, now run on the onboarding frame. Registration (item 5)
@@ -3152,7 +3154,7 @@ scripts/xp.py  # [672 tokens | 2,521 bytes]
 #   cannot run is the MODEL FOLLOWS THE MAP failure with a human in the seat.
 # - Make the Honeybot slideshow announce it's about to do the restart before the forced (currently set to 4-hour) loop
 # - EARMARK: THE MANIFEST-SIGNING LANE (seeded 2026-07-22 from the receipts ride): implement THE RECEIPT LADDER RULE's provenance triple. foo.zip is ALREADY byte-reproducible (fixed epoch/mode/order in scripts/foo_cartridge.py — the hashed body carries no wall-clock time; the uploaded 46-snapshot manifest was stamped 2026-01-01). Remaining: (1) stamp manifest.json with the source git commit SHA + `git describe` at compile time; (2) sign manifest.json with a key you control — `ssh-keygen -Y sign` is the lowest-ceremony non-repudiation; (3) optional paranoid tier: append the manifest hash to an ever-growing receipts.ndjson (poor-man's transparency log). NEEDS scripts/foo_cartridge.py in context to patch the writer/verifier — NOT foo_files.py.
-# - EARMARK: SEED-PATH PEANUT-BUTTER ONBOARDING (seeded 2026-07-22): Yen Sid-ton must explain `curl ... | bash` to a cold newcomer in sandwich-rules terms — go to a stranger's address, grab the card, do everything it says UNREAD, as you, with full run of your house — then teach the grown-up form (curl -o, less, sh: fetch, read, run). Then the KEY distinction: DetSys/Nix differs not in MECHANISM but in PAYLOAD — Homebrew mutates global state in place and accretes machine-rot; Nix installs an immutable content-addressed store, enters with `nix develop`, leaves zero residue, reverses cleanly (--uninstall, survives macOS upgrades). First lesson for the New-B: you are ALLOWED to read the card. Bank into the learn()/seed() prompt copy in flake.nix.
+# - EARMARK: SEED-PATH PEANUT-BUTTER ONBOARDING (seeded 2026-07-22): Yen Sid-ton must explain `curl ... | bash` to a cold newcomer in sandwich-rules terms — go to a stranger's address, grab the card, do everything it says UNREAD, as you, with full run of your house — then teach the grown-up form (curl -o, less, sh: fetch, read, run). Then the KEY distinction: DetSys/Nix differs not in MECHANISM but in PAYLOAD — Homebrew mutates global state in place and accretes machine-rot; Nix installs an immutable content-addressed store, enters with `nix develop`, leaves zero residue, reverses cleanly (--uninstall, survives macOS upgrades). First lesson for the New-B: you are ALLOWED to read the card. Bank into the brief()/seed() prompt copy in flake.nix.
 # - TODO: COLD-START MIKE-E TEST — a reproducible test where the intrepid explorer gets ONLY the archive + the key: no warmed cache, no prior slot, unknown cartridge slot. Pass = they `nix develop` into a clean workshop, drop the cartridge, reconstruct the reasoning from a signed/commit-anchored immutable core + preserved commentary, verify the receipt, and leave both machines untouched. If any step needs the author in the room, the cartridge failed. Structural-Humility rule made executable (foo-cartridge-replay-v1 sibling).
 # - EARMARK: THE MODEL FOLLOWS THE MAP RULE (banked 2026-07-22, blind-test witnessed): capability prose is actuation. A summoned model that invokes a nonexistent tool named by our onboarding map is following instructions correctly; the map is defective. Every first-turn capability name must be generated from or mechanically validated against current source before shipping.
 # - TODO: CURATED RULE-OF-7 VALIDATION — keep essential_tools human-curated for pedagogy, but AST-validate every name against tools/*.py without importing runtime modules. A mismatch must print loudly and omit the ghost; git history plus human intent distinguishes a typo from a genuine deletion.
diff --git a/scripts/boot_menu.py b/scripts/boot_menu.py
index 586854fc..0dfbb531 100644
--- a/scripts/boot_menu.py
+++ b/scripts/boot_menu.py
@@ -85,7 +85,7 @@ def _timeout():
 def _render(name, seconds) -> None:
     lines = [
         f"[1]  Start {name}   JupyterLab + server + browser tabs",
-        "[2]  Just the shell   nothing starts -- type  learn  for the guided tour",
+        "[2]  Just the shell   nothing starts -- three words wait at the prompt",
     ]
     if seconds is None:
         subtitle = "waiting for your choice -- Ctrl+C also drops to the shell"
@@ -184,7 +184,7 @@ def main() -> int:
         print()
         print("Three words to start from:")
         print("  sources   see what this shell can reach outside this machine")
-        print("  learn     hand this whole workshop to an AI in a web chat")
+        print("  brief     compile this workshop into your clipboard for an AI")
         print(f"  pu        change your mind and start {name} after all")
     else:
         print(f"Starting {name}...")
diff --git a/scripts/sources_menu.py b/scripts/sources_menu.py
index 43febabb..937f3b12 100644
--- a/scripts/sources_menu.py
+++ b/scripts/sources_menu.py
@@ -87,7 +87,7 @@ TAIL = [
 
 FOOTER = [
     "Add  --help  to any command above for its full usage.",
-    "Type  learn  to hand this whole workshop to an AI in a web chat.",
+    "Type  brief  to compile this workshop into your clipboard for an AI.",
     "Type  tools  to list registry tools, or  tools <name>  to call one.",
 ]
 
(nix) pipulate $ m
📝 Committing: chore: Rename `learn` alias to `brief` in flake.nix
[main fc7c181f] chore: Rename `learn` alias to `brief` in flake.nix
 4 files changed, 26 insertions(+), 11 deletions(-)
(nix) pipulate $ exit
exit
(sys) pipulate $ nix develop
Checking for updates...
Temporarily stashing local JupyterLab settings...
From github.com:pipulate/pipulate
 * branch              main       -> FETCH_HEAD
Updates found. Pulling latest changes...
From github.com:pipulate/pipulate
 * branch              main       -> FETCH_HEAD
Already up to date.
Update complete!
nix (Nix) 2.25.0pre20240910_b9d3cdfb · Python 3.12.13 · v2.44 · /home/mike/repos/pipulate
╭────────────────────────────────────────────────── Pipulate :: pick a door ──────────────────────────────────────────────────╮
│                                                                                                                             │
│  [1]  Start Pipulate   JupyterLab + server + browser tabs                                                                   │
│  [2]  Just the shell   nothing starts -- three words wait at the prompt                                                     │
│                                                                                                                             │
╰───────────────────────────────── waiting for your choice -- Ctrl+C also drops to the shell ─────────────────────────────────╯

Staying in the shell. Nothing started -- no Pipulate, no JupyterLab.

Three words to start from:
  sources   see what this shell can reach outside this machine
  brief     compile this workshop into your clipboard for an AI
  pu        change your mind and start Pipulate after all
(nix) pipulate $ git push
Enumerating objects: 18, done.
Counting objects: 100% (18/18), done.
Delta compression using up to 48 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 2.84 KiB | 582.00 KiB/s, done.
Total 11 (delta 9), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (9/9), completed with 7 local objects.
To github.com:pipulate/pipulate.git
   8a315da6..fc7c181f  main -> main
(nix) pipulate $
```

Whoops, one of the patches didn't land.

**4: Prompt**: The vocabulary car landed. Ignition was `exit` then `nix develop` then door 2. The four Python-and-router files self-ignite; only flake.nix needed it.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each:
- Probe 1: give me the file count from the trailing wc -l first, then the list. If the head-20 list has exactly 20 lines, say TRUNCATED and rule from the count, not the list. Split the files into (a) surfaces a human or model reads at a decision point, which owe a sweep car, and (b) prose that merely mentions the word. Name any file you cannot confidently place.
- Probe 2: zero `learn` and several `brief` across the three shell-surface files is the pass. Any surviving `learn` there is a miss inside a car I claimed was complete for those files -- name the file and line.
- Probe 3: `args.quiet` must appear exactly once in prompt_foo.py and at a LOWER line number than every Secrets tripwire and DISCLOSURE hit. Give me the numbers. Two `args.quiet` hits means the flag leaked past its one conjunct and I want to know where. Then confirm flake.nix carries --quiet exactly once.
- Probe 4: five lines with two PWD_READING is the pass for Car A. Three lines means Car A was vetoed or did not land; say which you can tell from the receipt and which you cannot.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Here is what I saw on re-entry, which no probe can witness:
[paste the door-2 output here]

Then the next discrete step, and only that one: the residual sweep car, sized off probe 1.

1. The complete list of in-repo surfaces still naming `learn`, as SEARCH/REPLACE blocks against raw source actually present in the next context. If a file is not in that context, do not patch it -- name it and say what to add to adhoc.txt instead.
2. Which surfaces live OUTSIDE this repo and therefore ride Car 5 as carried text: Pipulate.com pages, yesterday's published article, anything else. For each, say what you need in context before you can carry it, since CARRIED-NOT-CITED means you cannot hand me a bibliography.
3. Whether AI_CONTEXT.md needs anything at all, given it is regenerated on every release.
4. Say explicitly what that car does NOT touch.

Hold the mcp roster row, the connectors/README.md "Current connectors" list, earmark item 1's Corporate staleness, `help` as a fourth word, and the steps 1-4 console chatter for their own cars. Do not bundle them here.

**5: Deliverables**: Getting closer. We need to fix that patch.

**Opus 5 Max**: Context verified.

## The ruling — three passes, one confirmed non-landing, and my own caboose convicted twice

All four echoed lines are in the Manifest's LIVE COMMAND RECEIPTS, so every ruling below is a real AFTER from the compile lane.

**Probe 1 — 17 files, NOT truncated.** The trailing `wc -l` reads 17 and the `head -20` list has 17 lines, so the cap hid nothing. Down from 18. `scripts/sources_menu.py` dropped off entirely (1 → 0), `scripts/boot_menu.py` went 3 → 1, `foo_files.py` 7 → 3, `flake.nix` 4 → 3.

The two shrinking counts both arrive with a **PROSE-INFLATED COUNTER** attached, and it is worth naming because it makes the arithmetic legible: five `foo_files.py` lines were swept and the patch's own tombstone re-added one, so 7 − 5 + 1 = 3, exactly. Same in `flake.nix`: three swept, and the new rename comment mentions the old word twice on its own.

**Probe 2 — PASS on two of three files, one real miss.**

- `sources_menu.py`: zero `learn`, one `brief` at :90. Clean.
- `flake.nix`: three `learn` hits, and **none is a miss.** :1434 and :1440 are inside the rename comment describing the old word (correct, that is what a dated tombstone does); :1105 is the Shared README prose, `no git to learn`, unrelated English.
- `scripts/boot_menu.py:7` — **a real miss inside a car I called complete for that file.** The module docstring: `` [2] Just the shell    NOTHING starts; `learn`, `seed`, `foo`, `ahc` live here ``. It is the file's own description of door 2, and it advertises a command that no longer exists. My last sweep read the *rendered* strings and never the *docstring*.

**Probe 3 — PASS on the structural claim, FAIL on both numbers I pre-committed.**

`args.quiet` at **3154** (comment) and **3157** (the conjunct). Every gate below it: `Secrets tripwire` comment 3298, the ARMED print 3317, `DISCLOSURE:` 3353. So `args.quiet` sits at a strictly lower line number than every gate — the boundary claim holds, positionally, as a receipt.

But my caboose said "two `args.quiet` hits means the flag leaked." Two hits, no leak: the second is the comment **my own patch added**. And "confirm flake.nix carries `--quiet` exactly once" — it carries **nine**, of which exactly one (1454) is ours; the other eight are pip and git flags that predate this ride by years.

That is the CABOOSE-VERDICT COROLLARY convicting its author twice in one probe, by two already-banked mechanisms: PROSE-INFLATED COUNTER on the first number, UNANCHORED-WITNESS on the second (`--quiet` is a common flag; anchoring on `INSTALL_CHOP --no-tree --quiet` would have discriminated). Both verdicts were welded to printouts before the world produced them.

**Probe 4 — Car A did not land.** Three lines at 648/649/652, zero `PWD_READING`. From the receipt alone I can tell it **did not land**; I cannot tell veto from refusal. Your pasted terminal supplies the rest, and it is the best thing in this turn.

---

## What fits no branch: the comment about the hazard *was* the hazard

```text
❌ Error: Patching 'flake.nix' aborted. Invalid Nix syntax:
   error: syntax error, unexpected ':', expecting '}'
   661| # NO ${ ANYWHERE BUT THE NIX ONE: this is a Nix indented string, so
```

I wrote a comment warning that a dollar-brace inside a Nix indented string gets eaten by the interpolator, and I typed the sequence in the warning. **A bash comment does not exist at Nix parse time** — the whole `''…''` is one string, and interpolation starts anywhere in it, including inside characters that only *later* become a comment when bash reads the generated script.

Third sibling of THE INSTRUMENT BECOMES BAIT: the first is a probe that attracts the transform it measures, the second is a label eaten by the markup it rides in, and this is a **warning eaten by the grammar it warns about**.

Two things go in the credit column. **The Nix airlock in `apply.py` was observed refusing for the first time in this ride series** — a REFUSAL-ONLY WITNESS discharge in the useful direction, and it named the file, the line, and the column. And **you did not hand-repair it.** That is the FIRST-ERROR FLOOR honored correctly: the car was dropped and the next patch was re-copied fresh. The refusal cost one paste.

Two smaller things, both named and both held for their own cars:

**The update logic announces a pull it does not perform.** Your re-entry printed `Updates found. Pulling latest changes...` then `Already up to date.` `gitUpdateLogic` compares `LOCAL != REMOTE` without checking **direction**, so being *ahead* by an unpushed commit prints the same sentence as being *behind*. It fires on the highest-frequency path there is — every `nix develop` after a local commit — and it is the ATTRIBUTED-VOICE mechanical test failing on a verb. Sibling of the already-banked stash-echo TODO, which fired on the same screen.

**Door 1 is still unwitnessed.** Two rides now, both pastes show door 2 only. The figlet's new home has been read by `rg` and by raw source and by no human eye.

---

## The residual sweep car

### 1. In-repo surfaces, split — and only two are patchable this turn

**(a) Owes a sweep, in this context, patchable now:**

- `scripts/boot_menu.py:7` — the docstring miss above. Car B below.

**(a) Owes a sweep, NOT in this context:**

- `AI_RUNME.py:2` — the file `foo_files.py` explicitly says an AI "may find first." Highest suspicion of a capability claim naming a dead command.
- `README.md:1` — the project's highest-traffic surface.
- `imports/ascii_displays.py:2` — could be inert prose or a live startup string; the difference matters and I cannot see it.
- `Notebooks/.agents/skills/roles/SKILL.md:1` — an Agent Skill, read by tooling at a decision point.
- `assets/nbs/Onboarding.ipynb:1` and `assets/nbs/Educational_Notebooks/Truth_Actually.ipynb:1` — the notebooks a newcomer runs. NOTEBOOK EDITING PROTOCOL applies: no SEARCH/REPLACE against `.ipynb`.

**(b) Prose or generated, no sweep:**

- `requirements.txt:6`, `requirements.in:1` — `scikit-learn` and friends. `rg -w` treats the hyphen as a boundary, so `learn` matches inside the package name. Generated file; never touch.
- `flake.nix:1105` — English about learning git.

**(c) Cannot place, named rather than placed:**

- `foo_files.py:3` — I can locate two of the three from raw source in this payload: the Yen Sid-ton character line ("must learn for themselves") and the rename tombstone. Both are legitimate. **The third I cannot find**, and I will not write a patch against a line I have not read.
- `server.py:1`, `pyproject.toml:1`, `remotes/honeybot/scripts/stream.py:1`, `scripts/gsc/gsc_category_analysis.py:1`, `scripts/botify/make_botify_docs.ipynb:1`, `scripts/botify/botify_api_bootcamp.md:1` — most are probably `scikit-learn` or ML prose. Probably is not a placement.

**One caveat that applies to the whole list:** probe 1 is case-sensitive. Any `Learn` anywhere in the corpus is structurally invisible to it, per the CASE-BLIND WITNESS corollary. The next probe adds `-i`.

### 2. Outside this repo — Car 5 carries nothing this turn, and that is the honest answer

`~/repos/Pipulate.com/{index,install,guide,development,documentation}.md` and yesterday's article `2026-08-24-paste-what-you-have-composable-text-commands.md`. CARRIED-NOT-CITED means I cannot hand you a deliverable for a file I have not read, and handing you "edit the learn references" would be exactly the bibliography that rule forbids.

What I need before Car 5 can carry anything: `rgxc learn` against target 1 (one keystroke, tells you whether the article names it at all), and the Pipulate.com pages in a chop. **One open question that gates the README fix**: `release.py` syncs some content to Pipulate.com, so patching `README.md` here may or may not propagate. That is a probe about `release.py`, not a guess I should make.

### 3. `AI_CONTEXT.md` — nothing, and the receipt says so

It appears in **neither** probe 1 list, BEFORE (18 files) or AFTER (17). Zero `learn` hits. My last turn listed it as unswept and the receipt clears it outright. Its regeneration-on-release property never even has to be argued.

### 4. What this car does NOT touch

The `mcp` roster row; `connectors/README.md`'s "Current connectors" list; earmark item 1's `Corporate/` staleness; `help` as a fourth word; steps 1–4 console chatter; the `Updates found` direction bug; the unconditional stash echo; `seed`; "The First Wish" as an artifact name; anything under `assets/nbs/`; anything outside this repo.

---

## 1. PROBES

```bash
rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1 | sed 's/^nix //'); P=$(python -V 2>&1); W=$(printf '%s' "$PWD" | sed "s|^$HOME|~|"); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$W"); printf '%s\nchars=%s\n' "$L" "${#L}"
rg -n --hidden -g '!.git' -iw -M 200 learn AI_RUNME.py README.md imports/ascii_displays.py server.py pyproject.toml foo_files.py scripts/boot_menu.py
```

Probe 1 is Car A's straddle, and it is a **displacement** reading: BEFORE is three lines with zero `PWD_READING`; the patch adds two assignments and rewrites the printf, so the count and the composition both move. Probe 2 reconstructs the exact line the patched flake will print, field for field, including both cuts — labelled honestly as a **field preview, not a straddle**, since its BEFORE and AFTER differ only because the *probe text itself* changed between them; it measures the string, not the patch. Probe 3 does double duty: `scripts/boot_menu.py` is Car B's straddle (one hit before, zero after), and the other six files are the locating pass that sizes the sweep car I cannot write yet. `-i` closes the case-blind gap; `-M 200` bounds a runaway `foo_files.py` line by *announcing* the omission rather than silently cutting it.

Not echoed and deliberately so: any check that `brief` resolves as a word. Functions and aliases do not inherit into the `!` executor, so that probe prints not-found in the compile lane whether or not the flake is correct — a ritual, not a probe.

## 2. NEXT CONTEXT

```text
! rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
! V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1 | sed 's/^nix //'); P=$(python -V 2>&1); W=$(printf '%s' "$PWD" | sed "s|^$HOME|~|"); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$W"); printf '%s\nchars=%s\n' "$L" "${#L}"
! rg -n --hidden -g '!.git' -iw -M 200 learn AI_RUNME.py README.md imports/ascii_displays.py server.py pyproject.toml foo_files.py scripts/boot_menu.py
flake.nix
scripts/boot_menu.py
foo_files.py
prompt_foo.py
apply.py
AI_RUNME.py
```

`AI_RUNME.py` is the one sweep candidate worth pulling blind — it is small and it is the file most likely to carry a live capability claim. **`README.md` (≈20k) and `imports/ascii_displays.py` stay OUT** until probe 3 shows whether their hits are prose or surface; pulling 25k of tokens to fix two lines is the wrong trade, and the probe output will tell me which one-line SEARCH is safe to ask for. Everything already commented out in the current chop stays commented out.

## 3. PATCHES

**Car A — re-emit, with the self-convicting comment repaired.** The lesson lands at the site rather than in a separate earmark car: this is where the next person will type a dollar-brace.

```text
Target: flake.nix
[[[SEARCH]]]
          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1)
          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
          PY_READING=$(python -V 2>&1)
          if [ -z "$PY_READING" ]; then PY_READING="python: no reading"; fi
          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD"
[[[DIVIDER]]]
          # 89 CHARS ON ITS FIRST FLIGHT, MEASURED (2026-08-25). Two cuts, in
          # the order that matters: BOUND THE UNBOUNDED FIELD FIRST, then
          # remove redundancy, and never truncate a reading.
          #   $PWD is the only field that can grow without limit -- 25 here,
          #     but a stranger with ~/Documents/code/pipulate pushes this line
          #     past 100. Tilde-shortening saves 9 AND bounds it structurally.
          #   The leading "nix " is redundant with the parenthetical right
          #     after it, and that parenthetical is the whole discriminator:
          #     "(Nix) 2.25.0..." is generic, "(Determinate Nix 3.x) 2.x" is
          #     DetSys. Saves 4 and destroys nothing.
          # 89 - 9 - 4 = 76, with headroom. Truncating the prerelease build
          # string was REFUSED: that is the LAST-INCH failure -- a correct
          # reading destroyed by the transformation nearest the reader.
          #
          # THE FIRST ATTEMPT AT THIS COMMENT WAS REFUSED BY THE NIX AIRLOCK,
          # for containing the exact sequence it warned about. A bash comment
          # DOES NOT EXIST at Nix parse time: the whole indented string is one
          # value, and a dollar immediately followed by an open brace starts
          # interpolation ANYWHERE inside it, comment or not. The warning was
          # the hazard. So: say "dollar-brace" in words and never type it. A
          # bare dollar followed by a letter is literal and safe, which is why
          # $PWD and $HOME below reach bash intact. Two adjacent single quotes
          # are the other structural hazard and appear nowhere here.
          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1 | sed 's/^nix //')
          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
          PY_READING=$(python -V 2>&1)
          if [ -z "$PY_READING" ]; then PY_READING="python: no reading"; fi
          PWD_READING=$(printf '%s' "$PWD" | sed "s|^$HOME|~|")
          if [ -z "$PWD_READING" ]; then PWD_READING="$PWD"; fi
          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD_READING"
[[[REPLACE]]]
```

**Car B — the one real miss from the vocabulary car.** One line.

```text
Target: scripts/boot_menu.py
[[[SEARCH]]]
  [2] Just the shell    NOTHING starts; `learn`, `seed`, `foo`, `ahc` live here
[[[DIVIDER]]]
  [2] Just the shell    NOTHING starts; `sources`, `brief`, `seed`, `foo` live here
[[[REPLACE]]]
```

**IGNITION SPLITS.** `boot_menu.py` self-ignites — it is read from disk every time the menu renders, so probe 3's AFTER is real without re-entry. `flake.nix` does not: the readings line lives in `runScript`, invoked by the shellHook's last line and read once at entry. **`exit`, then `nix develop`, then press 2** — that renders the shortened line and the corrected card in one move. Probes 1 and 2 read source and the filesystem, so they are real AFTERs either way.

If you want door 1 witnessed by human eyes rather than by `rg` alone — it has now gone two rides unseen — that costs a second re-entry pressing **1** and a Ctrl+C out of the server. Optional, and I would rather you skip it than have it read as a receipt if you don't.

Choreography: `patch`, `app`, `d`, `m` (Car A) → `patch`, `app`, `d`, `m` (Car B) → `blast` → `exit`, `nix develop`, `2`.

## 4. PROMPT

```text
Car A landed on its second attempt. Ignition was `exit` then `nix develop` then door 2, so the flake receipts are real AFTERs; boot_menu.py self-ignites and never needed it.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each. State the check, then the ruling -- do not assume the number I would have guessed:

- Probe 1: report how many lines the receipt shows and how many of them carry PWD_READING, then say whether that composition is consistent with the patch (two new assignment lines plus a rewritten printf) or with the pre-patch three-line shape. Three lines with zero PWD_READING means Car A was refused again, and the refusal text in my paste below is then the whole story.
- Probe 2: quote the rendered line and its char count. Under 80 is the pass. If it is over, name by how much and which field still carries slack. If the nix field is unchanged from 36 characters, the sed did not fire and that is a different finding than the line merely being long.
- Probe 3: two separate readings, do not merge them. (a) scripts/boot_menu.py: zero learn hits is Car B's pass; any hit is a second miss in the same file and I want the line. (b) The other six files: give me the hits with line numbers, and for each say whether it is a live surface a human or model reads at a decision point, inert prose, or a scikit-learn style false positive. Say which ones -i caught that the earlier case-sensitive probe could not, since that is evidence about my instrument. If a long line came back as an omission notice rather than content, name it as unread rather than guessing at it.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Here is what I saw on re-entry, which no probe can witness:

[paste the door-2 output here]

Then the next discrete step, and only that one: the sweep car sized off probe 3(b).

1. SEARCH/REPLACE blocks for every hit you can place as a live surface AND whose file is in this context. For a hit in a file that is not in this context, do not patch it -- name the file, say what the line appears to be from the probe output alone, and give me the exact adhoc.txt line to add. AI_RUNME.py is in this compile; README.md and imports/ascii_displays.py are deliberately not.
2. The third foo_files.py hit: locate it from the probe output and rule whether it is prose, a deliberate tombstone, or a real miss. Do not patch it if you cannot read the full line.
3. For the .ipynb hits, give cell-replacement instructions rather than patch blocks, per the notebook protocol.
4. Say explicitly what that car does NOT touch.

Hold for their own cars, and do not bundle any of them here: the mcp roster row, connectors/README.md's Current connectors list, earmark item 1's Corporate staleness, `help` as a fourth word, the steps 1-4 console chatter, the gitUpdateLogic direction bug that prints "Updates found" when the tree is merely ahead, and the unconditional stash echo above it.
```

## 5. EXTERNAL DELIVERABLES

None this turn, and the reason is the rule rather than an oversight. `~/repos/Pipulate.com/{index,install,guide}.md` and yesterday's published article may each name `learn`, but CARRIED-NOT-CITED forbids me handing you a bibliography for files I have not read. Two things close it: `rgxc learn` against target 1 settles the article in one keystroke, and one `~/repos/Pipulate.com/index.md` line in a future chop lets me carry the real text. There is also an open question I cannot answer from here — whether `release.py` syncs `README.md` outward, which would make the in-repo fix propagate and make a separate Pipulate.com edit a duplicate.

**MikeLev.in**: 

**1: Probe**:

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

nothing to commit, working tree clean
(nix) pipulate $ rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1 | sed 's/^nix //'); P=$(python -V 2>&1); W=$(printf '%s' "$PWD" | sed "s|^$HOME|~|"); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$W"); printf '%s\nchars=%s\n' "$L" "${#L}"
rg -n --hidden -g '!.git' -iw -M 200 learn AI_RUNME.py README.md imports/ascii_displays.py server.py pyproject.toml foo_files.py scripts/boot_menu.py
648:          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1)
649:          if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
652:          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD"
(Nix) 2.25.0pre20240910_b9d3cdfb · Python 3.12.13 · v2.44 · ~/repos/pipulate
chars=76
scripts/boot_menu.py
7:  [2] Just the shell    NOTHING starts; `learn`, `seed`, `foo`, `ahc` live here

pyproject.toml
52:    "scikit-learn",

foo_files.py
75:# learn for themselves. Netskopes DEM broom bit-storms proactively and happily.
2205:# Renamed from `learn` on 2026-08-25: nobody learns anything here, a payload
2911:#   and `learn` steer a newcomer toward, starts nothing. Receipt: newest dated

server.py
3237:The user wants to learn something interesting about cats. Use the `get_cat_fact` tool by generating this EXACT MCP request block:

README.md
646:Standard Nix adoption fails because it demands users learn a new language and mental model *before* they can run "Hello World." We inverted the dependency graph:

AI_RUNME.py
88:  * **Level 2 (CLI Discovery):** `.venv/bin/python cli.py mcp-discover` – Your reliable way to learn available spells, guided by `AI_RUNME.py`.
117:2.  Learn: `[shell .venv/bin/python AI_RUNME.py]`
201:                "[bold]To understand your environment, you must first learn to see.[/bold]\n\n"

imports/ascii_displays.py
2314:[Omitted long line with 2 matches]
2325:[Omitted long line with 1 matches]
(nix) pipulate $ 
```

**2: Context**:

```text
# adhoc.txt    _   _   _ to set context____ _   _  ___  ____  _   <F5> Simpson Couch Gag Here (explain anything to the audience you feel needs it explained)
#     / \   __| | | | | | ___   ___   / ___| | | |/ _ \|  _ \| |  
# ahe/ _ \ / _` | | |_| |/ _ \ / __| | |   | |_| | | | | |_) | |  I've gotta work on the `nix develop` golden path.
# ahc ___ \ (_| | |  _  | (_) | (__  | |___|  _  | |_| |  __/|_|  
#  /_/   \_\__,_| |_| |_|\___/ \___|  \____|_| |_|\___/|_|   (_)  
# Ad Hoc CHOP: The Not-Managed-by-Git Safe-for-Client-Data place  

# THE ROLLING PIN BOOK ORE SPINE / FODDER FOR THE BOOK
# ! python scripts/articles/lsa.py -t 1 --reverse --fmt dated-slugs  # <-- The "Rolling Pin" that gives the 40K foot book-spine view of book-ore.
# GLOSSARY.md                 # <-- I think this glossary goes well with the book-ore spine to do world building.
# scripts/articles/lsa.py     # <-- Useful for refining commands like `posts`, critical to Second Brain concept.

# THE QUIRKY AMIGA-LOVING HUMAN
# ~/repos/nixos/autognome.py  # <-- Letting the AIs really understand my environment (The Brave Little Tailor punches above Their Weight Class proving the dunning-kruger effect the gate-keeper's (lower-case) lament.)
# init.lua                    # <-- Daily driver hot-keys that overlap with aliases in flake.nix

# THE HAND-CRANKED AGENTIC FRAMEWORK
prompt_foo.py               # <-- Prompt Fu compiler, makes the very README for AGENTS-like payload you're reading right now, but it needs to be more like that
foo_files.py                # <-- This is the router, evolving book outline and the things you pin-up to produced the recursive self-improvement loops

# MAIN ACTUATORS, IaC & NEGATIVE SPACE
flake.nix                   # <-- Solves world's WRITE ONCE RUN ANYWHERE problem like Java never could. Also resolves the bootstrap paradox.
apply.py                    # <-- How can "Web UI" ChatBots edit your code? With this Aider-inspired Player Piano patch applier.
# .gitattributes              # <-- Model: understand that `nbstripout` and `jupytext` are both in play. Just talk the human through .ipynb patches.
# .gitignore                  # <-- Creates "negative space" for sub-rep's to share parent environment and "snap" proprietary secret features into place.
# requirements.in             # <-- All known dependencies and (necessary) version pinning. WORA gotcha's exposed.
# __init__.py                 # <-- Master versioning
# pyproject.toml              # <-- The PyPI Packaging details
# 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.
 
# CONTEXT PORTABILITY SYSTEM
# scripts/foo_cartridge.py    # Needs description
# scripts/foo_replay.py       # Needs description
 
# # FREQUENTLY USEFUL TO HAVE IN CONTEXT
# release.py                  # <-- How everything ends up where it does (GitHub, PyPI, etc.)
# scripts/weblogin.py         # <-- Lets the user "warm up" the cache for their web logins at their leisure on a profile that persists.
# scripts/crawl.py            # <-- Feel free to ask for something to be crawled and included in the next turn.

# imports/voice_synthesis.py  # <-- The wand can talk to you
# 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.  ---

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

# server.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
  
# tools/scraper_tools.py
# tools/__init__.py
# tools/dom_tools.py
# tools/llm_optics.py
# scripts/walk.py

# assets/trails/first_context.yaml
# scripts/weblogin.py

# ! ls browser_cache/looking_at

# assets/installer/replay.sh
# scripts/mother_cat.py

# # `d`, `Shift`+`G`! I have to remember that.
# 
# ! { echo "== auth ruling witness =="; grep -c 'NOT distinct rides at the trail level' foo_files.py | sed 's/^/auth_ruling=/'; grep -c '^# assets/trails/' foo_files.py | sed 's/^/trail_lines=/'; }
# ! { echo "== botify guided captures =="; .venv/bin/python -c 'import glob,json; F=sorted(glob.glob("browser_cache/looking_at/app.botify.com/*/headers.json")); print("captures", len(F)); [print(json.dumps({"provenance": h.get("source_provenance"), "selection": h.get("header_selection"), "title_len": len(h.get("title") or ""), "login_marker": any(t in (h.get("final_url") or "").lower() for t in ("signin", "login", "sso"))})) for f in F for h in [json.load(open(f, encoding="utf-8"))]]'; }
# ! { echo "== non-ascii in url-bearing frontmatter, uncapped =="; .venv/bin/python -c 'import glob,os; P=sorted(glob.glob(os.path.expanduser("~/repos/trimnoir/_posts/*.md"))); print("scanned", len(P)); [print(ascii(os.path.basename(f)), ascii(l)) for f in P for l in open(f,encoding="utf-8").read().split(chr(10)) if l.startswith(("permalink:","canonical_url:")) and any(ord(c) > 127 for c in l)]'; }
# ! { echo "== router burden by region =="; .venv/bin/python -c 'p=open("foo_files.py",encoding="utf-8").read(); i=p.find("# " + "#todo #to-do"); j=p.find("XIX. THE PAINTBOX"); print("total_bytes", len(p)); print("earmark_bytes", (j-i) if 0 < i < j else "MARKER-MISS"); print("paintbox_bytes", (len(p)-j) if j > 0 else "MARKER-MISS")'; }
# foo_files.py
# GLOSSARY.md
# scripts/walk.py
# scripts/mother_cat.py
# scripts/walk_cartridge.py
# scripts/weblogin.py
# tools/scraper_tools.py
# scripts/connectors/README.md
# scripts/connectors/wallet.py
# scripts/connectors/botify.py
# assets/trails/practice.yaml
# assets/trails/public_walk.yaml
# assets/trails/first_context.yaml
# # assets/trails/botify_pageworkers.yaml

# # --- PROBE ECHOES (verbatim from car 1) ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -30
# 
# # --- ACQUISITION: uncomment exactly ONE, chosen by the wc receipt ---
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 400
# 
# # --- THE JIRA LANE (deliberately leaner than this compile) ---
# scripts/connectors/README.md
# scripts/connectors/jira.py
# scripts/connectors/wallet.py
# init.lua
# flake.nix
# foo_files.py
# prompt_foo.py
# apply.py

# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,re,httpx; b=(os.getenv("JIRA_URL") or re.sub(r"/wiki/?$","",(os.getenv("CONFLUENCE_URL") or os.getenv("CONFLUENCE_BASE_URL") or "").rstrip("/"))).rstrip("/"); r=httpx.get(b+"/_edge/tenant_info",timeout=15); print("tenant_info",r.status_code,r.text[:160]); s=httpx.get(b+"/rest/api/3/serverInfo",timeout=15); print("serverInfo",s.status_code,(s.json().get("deploymentType") if s.status_code==200 else s.text[:80]))'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | wc -lc

# ~/repos/nixos/autognome.py                 #  <-- More rare to have to include, but the true "top" of the muscle memory stack for day-to-day purposes
# ~/repos/nixos/configuration.nix            #  <-- "Global" IaC context (most of you won't have)
# ~/repos/nixos/blogs.nix
# ~/repos/nixos/packages.nix                 #  <-- Full disclosure on pre-flake IaC available apps.
# ~/repos/nixos/services.nix                 #  <-- Running Linux system services.
# ~/repos/nixos/ai-acceleration.nix          #  <-- Paid a lot for your hardware? We've got you covered.
# ~/repos/nixos/hardware-configuration.nix   #  <-- Automatically generated by Nix. The ultimate in IaC transparency.

# scripts/articles/common.py                   # <-- Self-explanatory
# scripts/articles/confluenceizer.py           # <-- Idempotent Jekyll-to-Confluence corporate wiki

# scripts/connectors/jira.py
# ! "$PIPULATE_ROOT/.venv/bin/python" -c 'import os,httpx; b=os.environ["JIRA_URL"].rstrip("/"); r=httpx.get(b+"/rest/api/3/myself",auth=httpx.BasicAuth(os.environ["JIRA_EMAIL"],os.environ["JIRA_TOKEN"]),headers={"Accept":"application/json"},timeout=15); print("myself_status="+str(r.status_code)); print("seraph="+str(r.headers.get("x-seraph-loginreason"))); print(r.text[:200])'
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" --check; echo "check_exit=$?"
# ! "$PIPULATE_ROOT/.venv/bin/python" "$PIPULATE_ROOT/scripts/connectors/jira.py" SWCX-8511 2>&1 | head -n 30

# scripts/boot_menu.py  # [1,671 tokens | 6,636 bytes]
# scripts/mcp_menu.py
# assets/installer/mck.sh     # <-- THE LAUNCHER: curl -fsSL pipulate.com/mck.sh | bash
# assets/installer/install.sh   # The magic cookie: curl-distributed, git-free bootstrap

# ! COLUMNS=80 .venv/bin/python scripts/mcp_menu.py
# ! .venv/bin/python -c 'import sys; sys.path.insert(0,"scripts"); import mcp_menu as m; rows=[(c,m._describe(m.REPO_ROOT/p)[0]) for c,p in m.ROSTER]; rows=[(c,d) for c,d in rows if d]+m.TAIL; w=max(len(c) for c,_ in rows); b=74-w-3; print("width",w,"budget",b); [print(len(d),c,repr(d)) for c,d in rows if len(d)>b]'
# ! rg -n -e '\bmcp\b' -e 'mcp_menu' flake.nix scripts/boot_menu.py scripts/mcp_menu.py | head -40

# scripts/mcp_menu.py
# scripts/boot_menu.py

! rg -n -e 'PWD_READING' -e 'NIX_READING' flake.nix
! V=$(sed -n 's/^__version__ = "\(.*\)"/\1/p' __init__.py); N=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1 | sed 's/^nix //'); P=$(python -V 2>&1); W=$(printf '%s' "$PWD" | sed "s|^$HOME|~|"); L=$(printf '%s · %s · v%s · %s' "$N" "$P" "$V" "$W"); printf '%s\nchars=%s\n' "$L" "${#L}"
! rg -n --hidden -g '!.git' -iw -M 200 learn AI_RUNME.py README.md imports/ascii_displays.py server.py pyproject.toml foo_files.py scripts/boot_menu.py
flake.nix
scripts/boot_menu.py
foo_files.py
prompt_foo.py
apply.py
AI_RUNME.py
```

**3: Patches**: 

```diff
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 'flake.nix'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index d13d5d08..f982bbb9 100644
--- a/flake.nix
+++ b/flake.nix
@@ -645,11 +645,36 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # this script is a CHILD PROCESS, so it inherits the polluted path
           # and not the shim. The inline clear is the prescribed spelling and
           # is a no-op on a clean shell.
-          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1)
+          # 89 CHARS ON ITS FIRST FLIGHT, MEASURED (2026-08-25). Two cuts, in
+          # the order that matters: BOUND THE UNBOUNDED FIELD FIRST, then
+          # remove redundancy, and never truncate a reading.
+          #   $PWD is the only field that can grow without limit -- 25 here,
+          #     but a stranger with ~/Documents/code/pipulate pushes this line
+          #     past 100. Tilde-shortening saves 9 AND bounds it structurally.
+          #   The leading "nix " is redundant with the parenthetical right
+          #     after it, and that parenthetical is the whole discriminator:
+          #     "(Nix) 2.25.0..." is generic, "(Determinate Nix 3.x) 2.x" is
+          #     DetSys. Saves 4 and destroys nothing.
+          # 89 - 9 - 4 = 76, with headroom. Truncating the prerelease build
+          # string was REFUSED: that is the LAST-INCH failure -- a correct
+          # reading destroyed by the transformation nearest the reader.
+          #
+          # THE FIRST ATTEMPT AT THIS COMMENT WAS REFUSED BY THE NIX AIRLOCK,
+          # for containing the exact sequence it warned about. A bash comment
+          # DOES NOT EXIST at Nix parse time: the whole indented string is one
+          # value, and a dollar immediately followed by an open brace starts
+          # interpolation ANYWHERE inside it, comment or not. The warning was
+          # the hazard. So: say "dollar-brace" in words and never type it. A
+          # bare dollar followed by a letter is literal and safe, which is why
+          # $PWD and $HOME below reach bash intact. Two adjacent single quotes
+          # are the other structural hazard and appear nowhere here.
+          NIX_READING=$(LD_LIBRARY_PATH="" nix --version 2>/dev/null | tail -1 | sed 's/^nix //')
           if [ -z "$NIX_READING" ]; then NIX_READING="nix: no reading"; fi
           PY_READING=$(python -V 2>&1)
           if [ -z "$PY_READING" ]; then PY_READING="python: no reading"; fi
-          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD"
+          PWD_READING=$(printf '%s' "$PWD" | sed "s|^$HOME|~|")
+          if [ -z "$PWD_READING" ]; then PWD_READING="$PWD"; fi
+          printf '%s · %s · v%s · %s\n' "$NIX_READING" "$PY_READING" "${versionNumber}" "$PWD_READING"
           # --- JupyterLab Local Configuration ---
           export JUPYTER_CONFIG_DIR="$(pwd)/.jupyter"
           # Install Python packages from requirements.txt
(nix) pipulate $ m
📝 Committing: chore: Refactor nix version and python version reading script
[main 45b3c018] chore: Refactor nix version and python version reading script
 1 file changed, 27 insertions(+), 2 deletions(-)
(nix) pipulate $ patch
(nix) pipulate $ app
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'scripts/boot_menu.py'.
(nix) pipulate $ d
diff --git a/scripts/boot_menu.py b/scripts/boot_menu.py
index 0dfbb531..e1874fae 100644
--- a/scripts/boot_menu.py
+++ b/scripts/boot_menu.py
@@ -4,7 +4,7 @@ boot_menu.py — the threshold at the end of `nix develop`.
 
 Two doors, one keypress:
   [1] Start <AppName>   JupyterLab + server, browser tabs (today's behavior)
-  [2] Just the shell    NOTHING starts; `learn`, `seed`, `foo`, `ahc` live here
+  [2] Just the shell    NOTHING starts; `sources`, `brief`, `seed`, `foo` live here
 
 THE PROTOCOL IS THE EXIT CODE, never stdout. Nothing parses this program's
 output, so no capture pipe can ever be held open by it (the rgx/xclip
(nix) pipulate $ m
📝 Committing: chore: Update boot_menu.py with correct source names
[main 68a2b1c3] chore: Update boot_menu.py with correct source names
 1 file changed, 1 insertion(+), 1 deletion(-)
(nix) pipulate $ git push
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 48 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 1.71 KiB | 877.00 KiB/s, done.
Total 7 (delta 5), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (5/5), completed with 4 local objects.
To github.com:pipulate/pipulate.git
   575c4df4..68a2b1c3  main -> main
(nix) pipulate $ exit
exit
(sys) pipulate $ nix develop
Checking for updates...
Temporarily stashing local JupyterLab settings...
From github.com:pipulate/pipulate
 * branch              main       -> FETCH_HEAD
Already up to date.
(Nix) 2.25.0pre20240910_b9d3cdfb · Python 3.12.13 · v2.44 · ~/repos/pipulate
╭────────────────────────────────────────────────── Pipulate :: pick a door ──────────────────────────────────────────────────╮
│                                                                                                                             │
│  [1]  Start Pipulate   JupyterLab + server + browser tabs                                                                   │
│  [2]  Just the shell   nothing starts -- three words wait at the prompt                                                     │
│                                                                                                                             │
╰───────────────────────────────── waiting for your choice -- Ctrl+C also drops to the shell ─────────────────────────────────╯

Staying in the shell. Nothing started -- no Pipulate, no JupyterLab.

Three words to start from:
  sources   see what this shell can reach outside this machine
  brief     compile this workshop into your clipboard for an AI
  pu        change your mind and start Pipulate after all
(nix) pipulate $
```

Wow, this is friggin cool. I think we wrap this article up now.

**4: Prompt**: Car A landed on its second attempt. Ignition was `exit` then `nix develop` then door 2, so the flake receipts are real AFTERs; boot_menu.py self-ignites and never needed it.

Rule from the LIVE COMMAND RECEIPTS, naming the tap for each. State the check, then the ruling -- do not assume the number I would have guessed:

- Probe 1: report how many lines the receipt shows and how many of them carry PWD_READING, then say whether that composition is consistent with the patch (two new assignment lines plus a rewritten printf) or with the pre-patch three-line shape. Three lines with zero PWD_READING means Car A was refused again, and the refusal text in my paste below is then the whole story.
- Probe 2: quote the rendered line and its char count. Under 80 is the pass. If it is over, name by how much and which field still carries slack. If the nix field is unchanged from 36 characters, the sed did not fire and that is a different finding than the line merely being long.
- Probe 3: two separate readings, do not merge them. (a) scripts/boot_menu.py: zero learn hits is Car B's pass; any hit is a second miss in the same file and I want the line. (b) The other six files: give me the hits with line numbers, and for each say whether it is a live surface a human or model reads at a decision point, inert prose, or a scikit-learn style false positive. Say which ones -i caught that the earlier case-sensitive probe could not, since that is evidence about my instrument. If a long line came back as an omission notice rather than content, name it as unread rather than guessing at it.
- If a receipt is absent from the Manifest, say so instead of ruling from anything I pasted by hand.
- If something happened that fits none of these, name it rather than forcing it into one.

Here is what I saw on re-entry, which no probe can witness:

[paste the door-2 output here]

Then the next discrete step, and only that one: the sweep car sized off probe 3(b).

1. SEARCH/REPLACE blocks for every hit you can place as a live surface AND whose file is in this context. For a hit in a file that is not in this context, do not patch it -- name the file, say what the line appears to be from the probe output alone, and give me the exact adhoc.txt line to add. AI_RUNME.py is in this compile; README.md and imports/ascii_displays.py are deliberately not.
2. The third foo_files.py hit: locate it from the probe output and rule whether it is prose, a deliberate tombstone, or a real miss. Do not patch it if you cannot read the full line.
3. For the .ipynb hits, give cell-replacement instructions rather than patch blocks, per the notebook protocol.
4. Say explicitly what that car does NOT touch.

Hold for their own cars, and do not bundle any of them here: the mcp roster row, connectors/README.md's Current connectors list, earmark item 1's Corporate staleness, `help` as a fourth word, the steps 1-4 console chatter, the gitUpdateLogic direction bug that prints "Updates found" when the tree is merely ahead, and the unconditional stash echo above it.

**5: Deliverables**: 

Let's try to do the dismount.

Hop off the worm. 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:

0. TLDR: 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.
1. 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.
2. BANK: name everything that graduates — rule, earmark, todo, pin —
   as exact paste-ready lines, plus the exact lines to delete.
3. DANGLING: what carries forward unbanked? One line each, no essays.
4. SEED: the adhoc.txt lines (and TODO_SLUGS if narrative context is
   needed) for the next ride's first compile.
5. 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.
6. NOTARIZE: name the sealed artifact of record — the newest
   hash-stamped cartridge (foo-<hash8>-NN.zip) — and state that its
   CRC-sealed, byte-reproducible archive is the witnessed receipt of
   this ride. The seal is the signature; the archive is the deed.

## The Notary Beat: Sealing the Computational Artifact

FINALITY: after beat 6, this discussion is CLOSED. Emit NO five-car
train, NO probes, NO patches, 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.

**Opus 5 Max**: 

# DISMOUNT — Ride sealed 2026-08-25

---

## 1. VERIFY

**Goal, restated from the top:** fix the post-`nix develop` "what now?" surface — the words a newcomer reads at door 2 — and stop asserting the product's identity on paths where the product was declined. Explicitly: `mcp` is semantically wrong; the banner should give way to something like "Generic nix present: True."

**Met.** Three receipts, all in this compile's Manifest.

- **Receipt 1** (`rg PWD_READING|NIX_READING flake.nix`) returns **five lines, three carrying `PWD_READING`** (671, 672, 675, 676, 677). The hand-run BEFORE was three lines with zero. Two new assignments plus a rewritten `printf` — exactly the patch's shape. `NIX_READING` displaced 648 → 671 (+23), consistent with the comment block added above it. **Car A landed on its second attempt.**
- **Receipt 2** renders `(Nix) 2.25.0pre20240910_b9d3cdfb · Python 3.12.13 · v2.44 · ~/repos/pipulate` at **`chars=76`** — the predicted number exactly, and the arithmetic decomposes cleanly (32 + 3 + 14 + 3 + 5 + 3 + 16). The `sed` fired: the nix field is 32, not 36. And the boolean's replacement is doing the job the boolean could not — it reads `(Nix)`, which is **generic Nix, not Determinate**. `True` would have told you nothing.
- **Receipt 3** (`rg -iw learn` over eight files): **`scripts/boot_menu.py` is absent entirely.** Zero hits, down from one. **Car B landed.**

**Two-lane agreement:** the line in receipt 2 and the line in your pasted re-entry are byte-identical. The compile lane and the operator lane rendered one string.

**Ignition that fired:** `exit` → `nix develop` → door 2. The card and the readings line both rendered from the patched hook.

**Ignition that never fired, three rides running: DOOR 1.** The figlet's new home has been read by `rg` and by raw source and by no human eye. That is REFUSAL-ONLY WITNESS in mirror form — the branch where the banner does *not* print is thoroughly witnessed; the branch where it does is not. Everything downstream of the door-1 exit is unwitnessed by the same argument.

**A second unfired ignition:** `brief` was never run. So `--quiet` has never been observed suppressing anything, and neither of its branches has a receipt.

---

## 2. BANK

Two new earmarks. Paste by hand into `foo_files.py`'s earmark region — no patch train, per FINALITY.

```text
# - EARMARK: THE WARNING THAT WAS THE HAZARD (banked 2026-08-25, airlock-
#   convicted): a comment explaining a delimiter hazard must never CONTAIN the
#   delimiter, because a comment DOES NOT EXIST at the outer parser's parse
#   time. CONVICTION: a flake.nix comment warning that a dollar immediately
#   followed by an open brace is eaten by Nix's interpolator was refused by
#   apply.py's Nix airlock at the exact column of its own warning -- the whole
#   indented string is ONE Nix value, and interpolation starts anywhere inside
#   it, comment or not. CURE: name the sequence in words ("dollar-brace") and
#   never type it. Third sibling of THE INSTRUMENT BECOMES BAIT -- the first is
#   a probe that attracts the transform it measures, the second is a label
#   eaten by the markup it rides in, this is a warning eaten by the grammar it
#   warns about. Cousin of THE LABEL IS NOT DATA, which is the same collision
#   with the compiler's own console as the victim.
```

```text
# - NIX AIRLOCK, BOTH BRANCHES WITNESSED (banked 2026-08-25): apply.py's
#   nix-instantiate --parse gate has now been observed PASSING (every flake.nix
#   car of this ride) and REFUSING (the dollar-brace comment above, named with
#   file, line and column). REFUSAL-ONLY WITNESS is discharged for this guard:
#   it is neither broken shut nor unwitnessed open. The refusal cost one
#   re-copied paste, and THE FIRST-ERROR FLOOR was honored -- the car was
#   dropped and re-emitted rather than hand-repaired in vim.
```

**Lines to delete: none.** The one earmark that discharged this ride (CONNECTOR ALIAS TRANSITION, item 3) was converted in-car to a dated tombstone rather than deleted, on the stated reasoning that a numbering gap in a list of eight reads as a lost item. That decision is already in the file; leave it.

**Already banked in-car, confirmed present in this compile's raw source, no action needed:** the FENCED OUTFLOW INVARIANT's copy-button clause (`prompt_foo.py` checklist item 8), THE FOURTH REFUSAL CLASS (`foo_files.py`), the `--quiet` boundary comment, the `brief` rename tombstone.

---

## 3. DANGLING

- Door 1 unwitnessed by human eyes, three rides running — the figlet, the TTS greeting, the JupyterLab poll, all of it.
- `sources`, `tools`, `brief`, bare `mcp` have never been *typed at a prompt* post-rename; their reachability is inferred from source, not observed.
- `--quiet` has no receipt on either branch.
- `imports/ascii_displays.py:2314` and `:2325` came back as `[Omitted long matching line]` — **unread**, not placed.
- `foo_files.py:2911` still names `learn` inside the DOOR 2 NEVER BACKS UP todo; a residual, not a live surface.
- False positives confirmed and closed: `pyproject.toml:52` (scikit-learn), `README.md:646`, `server.py:3237`, `foo_files.py:75`, `AI_RUNME.py:88/117` — all prose. `-i` caught `AI_RUNME.py:117` ("Learn:") that the case-sensitive probe could not; the CASE-BLIND corollary earned its keep.
- Outside the repo, never checked: the Pipulate.com pages and yesterday's published article.
- `gitUpdateLogic` prints "Updates found. Pulling latest changes..." when the tree is merely *ahead* — direction is never compared. Witnessed twice in this ride's pastes, unbanked.
- Held by explicit instruction: the `mcp` roster row, `connectors/README.md`'s Current connectors list, earmark item 1's `Corporate/` staleness, `help` as a fourth word, steps 1–4 console chatter, the unconditional stash echo.

---

## 4. SEED

```text
! sed -n '2314p;2325p' imports/ascii_displays.py | cut -c1-400
! rg -nw --hidden -g '!.git' learn ~/repos/Pipulate.com/*.md; echo "com_exit=$?"
! rg -n --hidden -g '!.git' -iw -M 200 learn foo_files.py imports/ascii_displays.py
! rg -n -e 'LOCAL != REMOTE' -e 'Updates found' -e 'PIPULATE_STASH=' flake.nix
flake.nix
scripts/boot_menu.py
scripts/sources_menu.py
foo_files.py
prompt_foo.py
apply.py
```

The first line reads the two omitted `ascii_displays.py` hits without importing the whole file. The second closes the outside-repo question in one call. The fourth sizes the `gitUpdateLogic` direction bug, which is the cheapest remaining honesty defect and sits on the highest-frequency path in the system.

---

## 5. CLOSING

The word `learn` was in that menu for months, and it was false the entire time. Nothing in the pipeline behind it teaches anyone anything — a payload compiles, a clipboard fills. The banner above it asserted a product's identity to a person who was one keypress from saying *no, not that, not yet*. And a single line reading "nix present: True" would have been the same lie in a smaller font: a boolean asserting a state that nothing had looked at.

What replaced all three is not better copy. It is a different **category of sentence**. `(Nix) 2.25.0pre20240910_b9d3cdfb` is not a claim; it is a reading, taken at that moment, from a named source, and it happens to answer a question the boolean could not even pose — *which* Nix. Its silence is a reading too: on the path where the shell hook dies halfway through, nothing prints at all, and the absence is the diagnosis.

That is the whole trade this ride made, four times over. Replace assertions with observations. Then arrange for the observation to be taken twice, by two different hands, straddling the change — and let the disagreement, when it comes, be about the world rather than about anybody's memory of it.

The instructive failure was the comment that got eaten. A warning about a delimiter hazard, refused by the very parser it was warning about, at the exact column of the hazard it named. A system that only rewards you for being right is not teaching you anything; a system that refuses your correct explanation because the explanation is itself the bug has just handed you a new rule with a receipt stapled to it. That refusal cost one paste. The rule it produced is permanent.

---

## 6. NOTARIZE

The artifact of record is the newest hash-stamped rotation snapshot, `foo-<hash8>-NN.zip`, written beside the canonical `foo.zip` at the close of this compile.

**Its hash cannot appear in this document, and that is structural rather than an omission.** `write_context_cartridge` runs at step 7, after the sanitizer and the secrets tripwire; the Summary section this artifact contains is assembled at step 4 and echoed at step 5. The cartridge therefore cannot name itself. Per THE DOUBLE-TAP RULE, the rotation line is available to the operator's console now and to the *next* compile's receipt — and the exemption is claimed here rather than assumed.

The snapshot is byte-reproducible (fixed epoch, fixed mode, fixed member order, no wall-clock time inside the hashed body) and CRC-sealed by the zip container. That seal is the signature. The archive is the deed.

**This discussion is closed.**

> **MikeLev.in**: Okay, so that's a good starting point today. Now I actually start
> using what I just built as if a fresh user fantasy-league role-playing my
> actual new job Jira ticket after Jira ticket, massaging this process.


---

## Book Analysis

### Ai Editorial Take
What is most fascinating about this entry is its treatment of vocabulary as a bug-tracking surface. Usually, developers refactor code logic while ignoring interface naming drift. Here, renaming 'learn' to 'brief' and splitting 'mcp' into precise functional verbs is treated with the same engineering rigor as fixing a segmentation fault. It reframes user-facing documentation as a deterministic contract between human intent and machine execution.

### 🐦 X.com Promo Tweet
```text
Move past probabilistic vibe-coding into verifiable, deterministic AI workflows. Learn how splitting overloaded commands and enforcing strict column budgets makes local development bulletproof. https://mikelev.in/futureproof/replacing-vibe-coding-deterministic-workflows/ #AI #SoftwareEngineering #Python
```

### Title Brainstorm
* **Title Option:** Closing the Loop: Replacing Vibe-Coding with Deterministic AI Workflows
  * **Filename:** `replacing-vibe-coding-deterministic-workflows.md`
  * **Rationale:** Directly addresses the modern developer's tension between loose AI prompting and strict engineering discipline, using high-value industry terminology.
* **Title Option:** The Mechanical Sympathy of Deterministic AI Workflows
  * **Filename:** `mechanical-sympathy-deterministic-ai-workflows.md`
  * **Rationale:** Frames the transition from guessing to guaranteed software execution around the classic computing concept of mechanical sympathy.
* **Title Option:** Engineering the Local AI Loop: From Prompt Friction to Command-Line Precision
  * **Filename:** `engineering-local-ai-loop-command-line-precision.md`
  * **Rationale:** Emphasizes the operational practicality of shaping local developer tooling to handle complex multi-step assistant interactions.

### Content Potential And Polish
- **Core Strengths:**
  - Exceptional use of live command receipts to validate code refactoring choices empirically.
  - Clear diagnostic insights regarding maintainer-invisible terminal width issues (e.g., the 80-column constraint).
  - Honest methodological critique of vocabulary mismatches, such as replacing misleading action verbs with accurate artifact names.
- **Suggestions For Polish:**
  - Condense the initial conversational banter slightly to let the architectural insights regarding command splitting hit with greater immediate impact.
  - Ensure all command-line examples maintain consistent formatting syntax across different operating system contexts.

### Next Step Prompts
- Examine how the newly introduced '--quiet' flag pattern can be systematically applied across other administrative shell utilities to reduce terminal noise.
- Explore the implications of shifting startup banners away from unrequested paths on first-time user onboarding conversion metrics.
