The Prefix Ladder and the Unalias Guard: Replayable Shell Ergonomics in the Age of AI

🤖 Read Raw Markdown

Setting the Stage: Context for the Curious Book Reader

In this chapter of the ongoing technical treatise, the spotlight shifts to the physical interface between human fingers and shell commands. In rapid human-AI iteration, even minor typing friction accumulates into cognitive friction. Here, the three foundational turn actions—prompting, context gathering, and payload compilation—are streamlined into single keystrokes (p, x, c) through prefix ladders that accept any truncation of the words. However, refining shell ergonomics exposes a subtle trap in Bash: pre-existing global aliases expanding inside subshell function definitions. What begins as a quest for fluid typing turns into an empirical demonstration of the unalias guard, illustrating how defensive environment isolation and verifiable receipts keep local development fast, stable, and checkable.

TL;DR: The workbench’s development shell is defined in a Nix flake. Its hook gives three shell commands that make up one turn of work with an AI chat. prompt saves the clipboard as the question. context edits the list of files the AI will read. compile combines both into one payload. This change makes every prefix of each command work, adds the one-letter forms p, x and c, and moves “cd to the project root” from p to h.

Before defining these functions, the hook clears any alias with the same name from the user’s bashrc. Bash would otherwise expand that alias inside the function definition and stop with a syntax error. A probe found two such aliases on the main machine. Typing the new words in a fresh shell confirmed the change. One of the automated checks failed for an unrelated Nix evaluation-cache reason and produced no reading.


Technical Journal Entry Begins

🔗 Verified Pipulate Commits:

MikeLev.in: I want to adjust my aliases or function names so that in addition to all the ones I already have for:

  1. prompt
  2. context
  3. compile

…I want to just be able to use:

  1. p
  2. x
  3. c

Keep all the previous aliases and function names to these same commands working. In fact if it doesn’t cause collisions and is not too ridiculous I want every abbreviation of the proper words they can think of to still work. So for prompt:

p pr pro prom promt

And for compile:

com comp compi compil compile

And for context:

con cont conte contex context

This just makes it nice and thorough and complete. Make it beautiful to look at in the flake if you can so it doesn’t cause people to vomit. And of course you can override any of this if I’m asking for things that conflict with very common Unix historical program names, but they have to still be in common enough modern use to justify the override ruling.

I know p conflicts with cd’ing to the pipulate home but I think that can just be h now for home since I use different folder names so frequently like the npvg.org and qamy.ai sites that p is no longer good and I want to be able to just tell people to type h to go to their Pipulate home directory which will get rid of that collision.

Engineering Prefix Ladders and Single-Letter Commands

Opus 5.5 Extra: Context verified.

What changes:

  • p, x and c become prompt, context and compile, and every prefix of each word works too.
  • h takes over p’s old job: cd to the Pipulate root.
  • pr now runs prompt instead of the coreutils print paginator. That tool is rarely typed by hand. The override only applies inside this shell, command pr still reaches the original, and scripts never see shell functions.
  • I added promp, the real five-letter prefix, and kept promt as a typo-catcher.
  • prompt becomes a function in each platform branch. Every rung now calls it, so its body exists in one place per platform instead of being copied.
  • An unalias line guards the new definitions. Bash expands an alias inside a function definition, so a stray alias p or alias c in ~/.bashrc or /etc/bashrc would otherwise cause a syntax error that stops the hook halfway. Probe 4 shows whether any such alias exists. If one does, it stops working inside the dev shell.

The Unalias Guard and Pre-Hook Collision Defense

1. PROBES

What each probe checks:

  • Probe 1: the generated hook still parses as bash.
  • Probe 2: lists the word definitions in the hook text. Before the patch it shows alias p, pro, prom, con, cont, com and comp. After the patch it shows alias h, the unalias line, all 16 rungs and two prompt() definitions.
  • Probe 3: proves the interactive alias read worked. A count above zero means the read is real.
  • Probe 4: names any pre-hook alias the unalias will clear.
  • Probe 5: finds docs or code that still teach p as home.

(nix) pipulate $

LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | bash -n && echo "hook parses"
LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | rg -n '^\s*(alias (h|p)=|unalias |(p|pr|pro|prom|promp|promt|prompt|x|con|cont|conte|contex|c|com|comp|compi|compil)\(\) )'
bash -ic alias </dev/null 2>/dev/null | rg -c '^alias '
bash -ic alias </dev/null 2>/dev/null | rg '^alias (h|p|pr|pro|prom|promp|promt|prompt|x|c|con|cont|conte|contex|com|comp|compi|compil)=' || echo "no pre-hook alias collides"
rg -n -g '*.md' -g '*.py' -g '*.lua' '`p`|alias p='

2. NEXT CONTEXT

scripts/boot_menu.py is included because the menu teaches the words and probably needs p, x, c and h added.

flake.nix
scripts/boot_menu.py
! LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | bash -n && echo "hook parses"
! LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | rg -n '^\s*(alias (h|p)=|unalias |(p|pr|pro|prom|promp|promt|prompt|x|con|cont|conte|contex|c|com|comp|compi|compil)\(\) )'
! bash -ic alias </dev/null 2>/dev/null | rg -c '^alias '
! bash -ic alias </dev/null 2>/dev/null | rg '^alias (h|p|pr|pro|prom|promp|promt|prompt|x|c|con|cont|conte|contex|com|comp|compi|compil)=' || echo "no pre-hook alias collides"
! rg -n -g '*.md' -g '*.py' -g '*.lua' '`p`|alias p='

3. PATCHES

Car 1 is flake.nix, five blocks in one fence. Two blocks must land together, which is why they share this car:

  • The alias p → alias h block. If alias p were still defined above the new p(), the hook would break.
  • The two platform blocks. Without them, prompt stays an alias.
Target: flake.nix
[[[SEARCH]]]
          alias p='cd "$PIPULATE_ROOT"'
[[[DIVIDER]]]
          # h goes home: cd to the Pipulate root, whatever the install folder
          # is called. It was p until 2026-10-01; p is prompt now (THE LADDERS).
          alias h='cd "$PIPULATE_ROOT"'
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
          # compile builds the payload (ahc); con, cont, pro, prom, com and
          # comp are the short spellings (cont, prom, comp is one rhythm and
          # con, pro, com another, 2026-09-27), and every old word stays.
          # FUNCTIONS, per THE ALIAS-DISPATCH RULE: prompt is an alias, so
          # pro carries the alias body instead of calling it,
          # and compile calls the ahc function so --profile and --reason
          # pass through. pro is defined beside prompt in the platform
          # branches below, because its body differs between pbpaste and
          # xclip. Typed by a human only; never echoed as a probe.
[[[DIVIDER]]]
          # compile builds the payload (ahc). Every prefix of each is the word
          # too (THE LADDERS, below), and every old word stays.
          # FUNCTIONS, per THE ALIAS-DISPATCH RULE: prompt was an alias until
          # 2026-10-01, which made pro copy its body; now it is a function in
          # each platform branch below (pbpaste or xclip), and compile calls
          # the ahc function so --profile and --reason pass through. Typed by
          # a human only; never echoed as a probe.
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
          con() { context "$@"; }
          cont() { context "$@"; }
          compile() { ahc "$@"; }
          com() { compile "$@"; }
          comp() { compile "$@"; }
[[[DIVIDER]]]
          compile() { ahc "$@"; }
          # THE LADDERS (2026-10-01): every prefix of the three words is the
          # word, so typing can stop at any letter and still land.
          #   prompt   p  pr   pro   prom   promp   promt  (the typo, kept)
          #   context  x  con  cont  conte  contex          (x: c is compile)
          #   compile  c  com  comp  compi  compil
          # Each rung calls the word, so each body lives once. pr shadows the
          # coreutils paginator in this shell only (command pr still reaches
          # it). The unalias clears any same-named alias from ~/.bashrc or
          # /etc/bashrc first: bash expands an alias inside a function
          # definition, and one stray alias p would stop the hook halfway.
          unalias p pr pro prom promp promt prompt x con cont conte contex c com comp compi compil 2>/dev/null || true
          p()      { prompt  "$@"; }
          pr()     { prompt  "$@"; }
          pro()    { prompt  "$@"; }
          prom()   { prompt  "$@"; }
          promp()  { prompt  "$@"; }
          promt()  { prompt  "$@"; }
          x()      { context "$@"; }
          con()    { context "$@"; }
          cont()   { context "$@"; }
          conte()  { context "$@"; }
          contex() { context "$@"; }
          c()      { compile "$@"; }
          com()    { compile "$@"; }
          comp()   { compile "$@"; }
          compi()  { compile "$@"; }
          compil() { compile "$@"; }
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
            alias prompt='(cd "$PIPULATE_ROOT" && pbpaste >prompt.md)'
            pro() { (cd "$PIPULATE_ROOT" && pbpaste >prompt.md); }
            prom() { pro "$@"; }
[[[DIVIDER]]]
            prompt() { (cd "$PIPULATE_ROOT" && pbpaste >prompt.md); }
[[[REPLACE]]]
Target: flake.nix
[[[SEARCH]]]
            alias prompt='(cd "$PIPULATE_ROOT" && xclip -selection clipboard -o >prompt.md)'
            pro() { (cd "$PIPULATE_ROOT" && xclip -selection clipboard -o >prompt.md); }
            prom() { pro "$@"; }
[[[DIVIDER]]]
            prompt() { (cd "$PIPULATE_ROOT" && xclip -selection clipboard -o >prompt.md); }
[[[REPLACE]]]

Ignition: the words exist only in a fresh shell. The AFTER probes read the hook text, so they need no ignition.

(nix) pipulate $

exit
nix develop

To check by hand after re-entry, type type p x c h at the prompt. This only works in an interactive shell, so it cannot be a ! line.

4. PROMPT

The ladders landed; the receipts above are the AFTER reading. Update scripts/boot_menu.py so the short word list teaches p (prompt), x (context), c (compile) and h (home), and fix any place probe 5 found that still teaches p as cd-home. If probe 4 named a pre-hook alias the unalias cleared, tell me which one and whether it needs to come back under another name. 5-Car Train.

Validating Keystrokes and Verifiable Payloads

5. EXTERNAL DELIVERABLES

None.

MikeLev.in:

THE AI-EDIT METHOD

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

1: BEFORE:

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

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | bash -n && echo "hook parses"
LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | rg -n '^\s*(alias (h|p)=|unalias |(p|pr|pro|prom|promp|promt|prompt|x|con|cont|conte|contex|c|com|comp|compi|compil)\(\) )'
bash -ic alias </dev/null 2>/dev/null | rg -c '^alias '
bash -ic alias </dev/null 2>/dev/null | rg '^alias (h|p|pr|pro|prom|promp|promt|prompt|x|c|con|cont|conte|contex|com|comp|compi|compil)=' || echo "no pre-hook alias collides"
rg -n -g '*.md' -g '*.py' -g '*.lua' '`p`|alias p='
hook parses
error: experimental Nix feature 'dynamic-derivations' is disabled; add '--extra-experimental-features dynamic-derivations' to enable it
38
alias c='cd ~/repos/pipulate/Workshop/personal/Client_Work/'
alias p='cd ~/repos/pipulate'
prompt.md
48:I know `p` conflicts with cd'ing to the pipulate home but I think that can just
50:npvg.org and qamy.ai sites that `p` is no longer good and I want to be able to

scripts/articles/sanitizer.py
139:# line break and without colliding with real code fences. `p` is shorthand
(nix) pipulate $ 

2: AFTER:

# # Context 1
# flake.nix
# release.py
# assets/installer/install.sh

# Context 2
flake.nix
scripts/boot_menu.py
! LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | bash -n && echo "hook parses"
! LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | rg -n '^\s*(alias (h|p)=|unalias |(p|pr|pro|prom|promp|promt|prompt|x|con|cont|conte|contex|c|com|comp|compi|compil)\(\) )'
! bash -ic alias </dev/null 2>/dev/null | rg -c '^alias '
! bash -ic alias </dev/null 2>/dev/null | rg '^alias (h|p|pr|pro|prom|promp|promt|prompt|x|c|con|cont|conte|contex|com|comp|compi|compil)=' || echo "no pre-hook alias collides"
! rg -n -g '*.md' -g '*.py' -g '*.lua' '`p`|alias p='

3: CHANGE:

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

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(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 'flake.nix'.
✅ DETERMINISTIC PATCH APPLIED: Successfully mutated 'flake.nix'.
(nix) pipulate $ d
diff --git a/flake.nix b/flake.nix
index e5bd873b..e6bef335 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1771,7 +1771,9 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           }
           alias vim='nvim'
           alias lsp='ls -d -1 "$PWD"/*'
-          alias p='cd "$PIPULATE_ROOT"'
+          # h goes home: cd to the Pipulate root, whatever the install folder
+          # is called. It was p until 2026-10-01; p is prompt now (THE LADDERS).
+          alias h='cd "$PIPULATE_ROOT"'
           alias foo='(cd "$PIPULATE_ROOT" && python prompt_foo.py --no-tree)'
           alias fu='(cd "$PIPULATE_ROOT" && python prompt_foo.py)'
           alias default='(cd "$PIPULATE_ROOT" && python prompt_foo.py --chop DEFAULT_CHOP --no-tree)'
@@ -1802,26 +1804,47 @@ runScript = pkgs.writeShellScriptBin "run-script" ''
           # THE HYPER-LITERAL WORDS (2026-09-25, the operator's ruling): the
           # three moves of a turn under names no meeting can call strange.
           # context opens context.txt, prompt captures the clipboard,
-          # compile builds the payload (ahc); con, cont, pro, prom, com and
-          # comp are the short spellings (cont, prom, comp is one rhythm and
-          # con, pro, com another, 2026-09-27), and every old word stays.
-          # FUNCTIONS, per THE ALIAS-DISPATCH RULE: prompt is an alias, so
-          # pro carries the alias body instead of calling it,
-          # and compile calls the ahc function so --profile and --reason
-          # pass through. pro is defined beside prompt in the platform
-          # branches below, because its body differs between pbpaste and
-          # xclip. Typed by a human only; never echoed as a probe.
+          # compile builds the payload (ahc). Every prefix of each is the word
+          # too (THE LADDERS, below), and every old word stays.
+          # FUNCTIONS, per THE ALIAS-DISPATCH RULE: prompt was an alias until
+          # 2026-10-01, which made pro copy its body; now it is a function in
+          # each platform branch below (pbpaste or xclip), and compile calls
+          # the ahc function so --profile and --reason pass through. Typed by
+          # a human only; never echoed as a probe.
           # ONE FILE, ONE WINDOW (2026-09-25): context opens context.txt and
           # nothing else. ahe below still opens foo_files.py as a second
           # buffer for whoever already types it; a newcomer's :q meets E173
           # ("1 more file to edit") on a second buffer they never visited,
           # and the notes the walk writes into this file teach :q.
           context() { (cd "$PIPULATE_ROOT" && "$(command -v nvim || command -v vim || echo vi)" "''${PIPULATE_ADHOC_FILE:-context.txt}"); }
-          con() { context "$@"; }
-          cont() { context "$@"; }
           compile() { ahc "$@"; }
-          com() { compile "$@"; }
-          comp() { compile "$@"; }
+          # THE LADDERS (2026-10-01): every prefix of the three words is the
+          # word, so typing can stop at any letter and still land.
+          #   prompt   p  pr   pro   prom   promp   promt  (the typo, kept)
+          #   context  x  con  cont  conte  contex          (x: c is compile)
+          #   compile  c  com  comp  compi  compil
+          # Each rung calls the word, so each body lives once. pr shadows the
+          # coreutils paginator in this shell only (command pr still reaches
+          # it). The unalias clears any same-named alias from ~/.bashrc or
+          # /etc/bashrc first: bash expands an alias inside a function
+          # definition, and one stray alias p would stop the hook halfway.
+          unalias p pr pro prom promp promt prompt x con cont conte contex c com comp compi compil 2>/dev/null || true
+          p()      { prompt  "$@"; }
+          pr()     { prompt  "$@"; }
+          pro()    { prompt  "$@"; }
+          prom()   { prompt  "$@"; }
+          promp()  { prompt  "$@"; }
+          promt()  { prompt  "$@"; }
+          x()      { context "$@"; }
+          con()    { context "$@"; }
+          cont()   { context "$@"; }
+          conte()  { context "$@"; }
+          contex() { context "$@"; }
+          c()      { compile "$@"; }
+          com()    { compile "$@"; }
+          comp()   { compile "$@"; }
+          compi()  { compile "$@"; }
+          compil() { compile "$@"; }
           # THE IDEATION DOOR: `idea` compiles IDEATION_CHOP (the constitution's
           # two forcing-function rules) primed for a 30-and-3 / axis-forcing
           # fan-out turn. A function, not an alias, so --profile/--reason pass
@@ -2464,9 +2487,7 @@ print('AI:\n', r.ai)
             alias xc='pbcopy <'
             alias xcp='pbcopy'
             alias xv='pbpaste >'
-            alias prompt='(cd "$PIPULATE_ROOT" && pbpaste >prompt.md)'
-            pro() { (cd "$PIPULATE_ROOT" && pbpaste >prompt.md); }
-            prom() { pro "$@"; }
+            prompt() { (cd "$PIPULATE_ROOT" && pbpaste >prompt.md); }
             alias patch='pbpaste >patch'
             # MAC SHADOW PUBLISHING: same sanitizer/articleizer mechanism,
             # deliberately no publish actuator: the Mac writes posts only into
@@ -2542,9 +2563,7 @@ print('AI:\n', r.ai)
             alias xcp='xclip -selection clipboard'
             alias xv='xclip -selection clipboard -o >'
             alias xp='(cd "$PIPULATE_ROOT" && python scripts/xp.py)'
-            alias prompt='(cd "$PIPULATE_ROOT" && xclip -selection clipboard -o >prompt.md)'
-            pro() { (cd "$PIPULATE_ROOT" && xclip -selection clipboard -o >prompt.md); }
-            prom() { pro "$@"; }
+            prompt() { (cd "$PIPULATE_ROOT" && xclip -selection clipboard -o >prompt.md); }
             alias patch='xclip -selection clipboard -o >patch'
             # Linux subshell aliases
             # write_post: unified, data-driven article intake. The privacy lane
(nix) pipulate $ m
📝 Committing: chore: Update Pipulate alias 'h' for navigating to Pipulate root
[main 00a3d8f5] chore: Update Pipulate alias 'h' for navigating to Pipulate root
 1 file changed, 39 insertions(+), 20 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 48 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 1.13 KiB | 386.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:pipulate/pipulate.git
   d479df85..00a3d8f5  main -> main
(nix) pipulate $ 

Ignition: often “exit”, “nix develop”. Instructions may vary.

Just as it says.

4: PROMPT:

The ladders landed; the receipts above are the AFTER reading. Update scripts/boot_menu.py so the short word list teaches p (prompt), x (context), c (compile) and h (home), and fix any place probe 5 found that still teaches p as cd-home. If probe 4 named a pre-hook alias the unalias cleared, tell me which one and whether it needs to come back under another name. 5-Car Train.

5: DELIVERABLE: Well this is a fun and easy one to check!

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

nothing to commit, working tree clean

GIT repo clean. Take BEFORE reading, make CHANGE, record AFTER diff.
(nix) pipulate $ p
(nix) pipulate $ x
(nix) pipulate $ c
╭────────────────────────────────────────────────── QA My AI (qamy.ai): Is what Claude said True? ──────────────────────────────────────────────────╮
│                                                                                                                                                   │
│                     ( Do you put your name on it because Claude said so? )                                                                        │
│                                           O        /)  __                                                                                         │
│ >  Do you think the Aviation industry      o /)\__//  /  \   "What Claude said" is a Cockpit                                                      │
│ >  vibe-codes without checking for       ___(/_ 0 0  |    |  Voice Recorder (CVR) hear-say of a                                                   │
│ >  confident hallucinations? So then   *(    ==(_T_)== QA |  subcontractor. This tool is a Flight                                                 │
│ >  why should you? If anyone relies on   \  )   ""\  |    |  Data Recorder (FDR) for High Reliability                                             │
│ >  your work then you should Q/A it.      |__>-\_>_>  \__/   Organizations (HROs). Use when it matters.                                           │
│                                                                                                                                                   │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
🗺️  Codex Mapping Coverage: 75.3% (210/279 tracked files) (was 210/279: +0 claimed, +0 tracked).
ROUTER LOADED: /home/mike/.local/state/pipulate/context.txt (7 active line(s))

✅ Topological Integrity Verified: 5 candidate reference(s) scanned, all exist.
   -> Executing: LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | bash -n && echo "hook parses" ... [10.4017s]
   -> Executing: LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | rg -n '^\s*(alias (h|p)=|unalias |(p|pr|pro|prom|promp|promt|prompt|x|con|cont|conte|contex|c|com|comp|compi|compil)\(\) )' ... [0.1221s]
   -> Executing: bash -ic alias </dev/null 2>/dev/null | rg -c '^alias '      ... [0.0257s]
   -> Executing: bash -ic alias </dev/null 2>/dev/null | rg '^alias (h|p|pr|pro|prom|promp|promt|prompt|x|c|con|cont|conte|contex|com|comp|compi|compil)=' || echo "no pre-hook alias collides" ... [0.0248s]
   -> Executing: rg -n -g '*.md' -g '*.py' -g '*.lua' '`p`|alias p='          ... [0.0204s]
Python file(s) detected. Generating codebase tree diagram... (3,086 tokens | 10,103 bytes)
Python file(s) detected. Generating UML diagrams...
   -> Generating for /home/mike/repos/pipulate/scripts/boot_menu.py... (skipped)
   -> Generating for /home/mike/repos/pipulate/apply.py... (skipped)
...UML generation complete.

   -> Ruff exit 0 (clean).
                                                          📦 Payload Ledger (biggest first)                                                          
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
┃ File / Source                                                                                                        ┃ Tokens ┃   Bytes ┃ % Bytes ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━┩
│ flake.nix                                                                                                            │ 39,359 │ 161,775 │   61.3% │
│ apply.py                                                                                                             │  8,892 │  38,326 │   14.5% │
│ PROMPT (checklist + prompt.md)                                                                                       │  8,642 │  32,805 │   12.4% │
│ AUTO: Codebase Structure (eza --tree + token sizes)                                                                  │  3,086 │  10,103 │    3.8% │
│ scripts/boot_menu.py                                                                                                 │  1,681 │   6,883 │    2.6% │
│ .gitignore                                                                                                           │  1,716 │   6,369 │    2.4% │
│ AUTO: Recent Git Diff Telemetry                                                                                      │  1,635 │   5,956 │    2.3% │
│ ! rg -n -g '*.md' -g '*.py' -g '*.lua' '`p`|alias p='                                                                │    456 │   1,387 │    0.5% │
│ ! LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | rg -n '^\s*(alias (h|p)=|unalias        │     56 │     235 │    0.1% │
│ |(p|pr|pro|prom|promp|promt|prompt|x|con|cont|conte|contex|c|com|comp|compi|compil)\(\) )'                           │        │         │         │
│ ! bash -ic alias </dev/null 2>/dev/null | rg '^alias                                                                 │     27 │      90 │    0.0% │
│ (h|p|pr|pro|prom|promp|promt|prompt|x|c|con|cont|conte|contex|com|comp|compi|compil)=' || echo "no pre-hook alias    │        │         │         │
│ collides"                                                                                                            │        │         │         │
│ .gitattributes                                                                                                       │     33 │      76 │    0.0% │
│ AUTO: Static Analysis Diagnostics                                                                                    │     11 │      39 │    0.0% │
│ ! LD_LIBRARY_PATH= nix eval --raw .#devShells.x86_64-linux.quiet.shellHook | bash -n && echo "hook parses"           │      2 │      11 │    0.0% │
│ ! bash -ic alias </dev/null 2>/dev/null | rg -c '^alias '                                                            │      1 │       2 │    0.0% │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼─────────┼─────────┤
│ TOTAL                                                                                                                │ 65,597 │ 264,057 │  100.0% │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────┴─────────┴─────────┘
**Command:** `prompt_foo.py --chop ADHOC_CHOP`

--- Auto-Context Metadata ---
• Codebase Structure (eza --tree + token sizes) (3,086 tokens | 10,103 bytes)
• Static Analysis Diagnostics (11 tokens | 39 bytes)
• Recent Git Diff Telemetry (1,635 tokens | 5,956 bytes)

--- Prompt Summary ---
Summed Tokens:    68,252 (from section parts)
Verified Tokens: 70,626 (from final output)
  (Difference: +2,374)
Total Words:      30,721 (content only)
Total Chars:      276,016
Total Bytes:      279,118 (UTF-8)

--- Size Perspective ---
📚 Equivalent in length to a **Novella or a Master's Dissertation** (Note: With a token/word ratio of 2.30, this content is far denser and more complex than typical prose of this length).
🧼 Identity scrub: substitutions=58 rule(s) | denylist=0 rule(s)
🔐 Secrets tripwire: ARMED -- 0 hit(s) in payload.
📦 Canonical QA archive written to /home/mike/repos/pipulate/qamy.ai.zip (sha256=c3e0a0affd2b…, members=3)
🗂️  Rotated archive snapshot: qamy.ai_1753-c3e0a0af.zip (keeping newest 20 of 20)
Markdown output copied to clipboard
(nix) pipulate $

Man is this system shaping up! It’s made for muscle memory and working at lightning speed (for a human).

Streamlining Editor Bindings for Rapid Dismounts

Oh I’m also changing the article-ending keyboard shortcut and getting rid of all that Gemini cleaning since I use webclip for that now.

(nix) pipulate $ vim init.lua 
(nix) pipulate $ d
diff --git a/init.lua b/init.lua
index 7787b466..0a3b6ea0 100644
--- a/init.lua
+++ b/init.lua
@@ -479,43 +479,6 @@ function add_liquid_raw_tags()
     vim.notify("Added raw tags around liquid syntax", vim.log.levels.INFO)
 end
 
-function clean_gemini_markdown()
-    -- Automatically enable wrap for visibility during the cleanup
-    vim.opt.wrap = true
-    
-    -- Save the starting cursor position so we can return to it for each step
-    local start_pos = vim.fn.getcurpos()
-    
-    -- Helper function to reset cursor, pause for the user, and execute
-    local function execute_step(step_num, desc, cmd)
-        -- Break the 'y' spam momentum and allow skipping
-        local prompt = "\nReady for Step " .. step_num .. "/4: " .. desc .. " [Press <Enter> to start, 's' to skip, or 'q' to abort] "
-        local user_input = vim.fn.input(prompt)
-        
-        if user_input:lower() == 'q' then
-            print("\nAborted cleanup sequence.")
-            return false
-        elseif user_input:lower() == 's' then
-            print("\nSkipped Step " .. step_num .. ".")
-            return true -- Return true to continue to the next step without executing the regex
-        end
-        
-        -- Return to the original starting line so '.,$' searches the same text block
-        vim.fn.setpos('.', start_pos)
-        
-        -- Execute the replacement safely
-        pcall(function() vim.cmd(cmd) end)
-        return true
-    end
-
-    if not execute_step(1, "Remove excessive backslashes", [[.,$s/\\\([\-+\[\]_#\*.]\)/\1/gc]]) then return end
-    if not execute_step(2, "Escape pipes in citations", [[.,$g/^\d\+\. /s/|/\\|/gc]]) then return end
-    if not execute_step(3, "Tag ambiguous inline footnotes", [[.,$s/\s\+\zs\(1\d\d\|[1-9]\d\|[1-9]\)\ze\s\+/<sup>&<\/sup>/gc]]) then return end
-    if not execute_step(4, "Wrap footnote numbers", [[.,$s/\([.):]\)\zs\(1\d\d\|[1-9]\d\|[1-9]\)\>\|\<\(1\d\d\|[1-9]\d\|[1-9]\)\ze[:,]\|\s\zs\(1\d\d\|[1-9]\d\|[1-9]\)\ze\s*$/<sup>&<\/sup>/gc]]) then return end
-
-    print("\nGemini Deep Research cleanup complete!")
-end
-
 function jump_next_active_chop()
     -- Search forward for the next line that is not purely blank 
     -- and does not start with a comment hash.
@@ -859,15 +822,12 @@ map('n', '<leader>j', '<cmd>lua new_journal_entry()<CR>', opts)  -- New journal
 map('n', '<leader>w', '<cmd>%s/\\s\\+$//e<CR>', opts)  -- Remove trailing whitespace
 map('n', '<leader>e', '<cmd>g/^\\n\\{4,}/d<CR>', opts)  -- Remove excessive blank lines (4+)
 
--- Clean up Gemini Deep Research Markdown
-map('n', '<leader>z', '<cmd>lua clean_gemini_markdown()<CR>', opts)
-
 -- Navigation
 map('n', '<leader>a', '<cmd>lua jump_next_active_chop()<CR>', opts)  -- Jump to next Active line (non-comment)
 
 -- Article / Workflow Selection
 map('n', '<leader>h', '<cmd>lua select_current_article()<CR>', opts)  -- Highlight (select) current article block
-map('n', '<leader>k', '<cmd>lua hop_off_sandworm()<CR>', opts)  -- Hop off: stage the dismount wrap-up above !!!
+map('n', '<leader>z', '<cmd>lua hop_off_sandworm()<CR>', opts)  -- Hop off: stage the dismount wrap-up above !!!
 
 -- Map it to <leader>p (for "Clip to Prompt")
 vim.api.nvim_set_keymap('v', '<leader>p', '<cmd>lua sync_to_prompt()<CR>', { noremap = true, silent = true })
(nix) pipulate $ m
📝 Committing: cleanup: chore: remove Gemini Deep Research cleanup code.
[main f490f110] cleanup: chore: remove Gemini Deep Research cleanup code.
 1 file changed, 1 insertion(+), 41 deletions(-)
(nix) pipulate $ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 48 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 350 bytes | 350.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:pipulate/pipulate.git
   00a3d8f5..f490f110  main -> main
(nix) pipulate $ 

And now I hit F2 and then backslash Z…

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

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

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

Nice.

Opus 5.5 Extra: Context verified.

Empirical Verification and the Deciding Keystroke

1. VERIFY

The goal was p/x/c plus prefix ladders for prompt, context and compile, every old word still working, and p (cd home) moved to h. Met.

Evidence from this compile:

  • flake.nix body (Codebase):
    • alias h= is present, and no alias p= or alias prompt= remains.
    • The unalias line and all 16 rung functions are present.
    • prompt() is a function in both the Darwin and Linux branches.
  • Receipt 1 (hook parses): this is supporting evidence only. The pipeline’s exit status is bash -n’s, so it would print the same line if nix eval failed. The hand-run BEFORE printed exactly one Nix error, and that error belongs to line 2, so line 1’s eval did produce the hook text.
  • Receipt 2 failed in both worlds: experimental Nix feature 'dynamic-derivations' is disabled. It ran in 0.12 s, against 10 s for the identical eval in receipt 1. That points at the eval cache, which is not yet proven. The hook-text straddle therefore never produced a reading. This is not a regression, because the BEFORE failed the same way.
  • Receipts 3 and 4:
    • 38 pre-hook aliases were read.
    • Two of them collide: alias p='cd ~/repos/pipulate' and alias c='cd ~/repos/pipulate/Workshop/personal/Client_Work/'.
    • So the unalias guard is load-bearing, not paranoia.
  • Receipt 5: no doc teaches p as home. The prompt.md hits are this conversation. sanitizer.py:139 uses p for something else, a shorthand in a comment about code fences.
  • Human witness (the operator’s paste):
    • c ran a full compile and wrote cartridge 1753. The pre-hook alias would have changed directory to Client_Work instead. This proves three things: ignition fired, unalias ran, and c() resolves.
    • p lands in the same folder either way, so it cannot be told apart on its own. It is covered transitively, because the same unalias line and the same block define both letters.
    • x printed no “command not found”.

Ignitions:

  • exit then nix develop fired, witnessed by c.
  • F2 for init.lua fired, witnessed by \z producing this turn.
  • None is missing.
  • The missing piece is a reading, probe 2’s hook-text AFTER, not an ignition.

2. BANK

One car: it records the witness beside the guard, so a later cleanup does not delete unalias as paranoia.

Target: flake.nix
[[[SEARCH]]]
          # definition, and one stray alias p would stop the hook halfway.
[[[DIVIDER]]]
          # definition, and one stray alias p would stop the hook halfway.
          # WITNESSED 2026-10-01: on Prime, bash -ic alias read alias p (cd to
          # the repo) and alias c (cd to Client_Work) before this hook, and c
          # typed after re-entry ran compile. Load-bearing; never delete it as
          # paranoia. Outside the dev shell those two letters still mean cd.
[[[REPLACE]]]

Ignition for this car: none required. It is a comment.

3. DANGLING

  • Probe 2 never read: a second nix eval fails with “dynamic-derivations disabled”. The suspected cause is the eval cache, and --no-eval-cache is the test.
  • Probe 1 cannot discriminate: it prints hook parses even when the eval fails. It needs pipefail.
  • Pre-hook c (cd to Client_Work) is gone inside the dev shell and has no replacement. If it is used inside the dev shell, it needs a new name such as cw. This answers last turn’s question.
  • The system aliases still mean cd outside the dev shell: p and c mean cd in the plain shell and prompt/compile in the dev shell. Likely source is ~/repos/nixos/configuration.nix. Rename those (p → h) or accept the split.
  • The boot_menu.py BLANK STARE RULE conflicts with the request:
    • The rule says the menu prints plain words and never abbreviations. So p, x and c stay off the menu by design.
    • h has no plain word behind it, such as home, so the menu cannot teach it without one.
    • This needs a ruling before anything is patched.
  • \k was freed and hop-off moved to \z: any doc or foo_files.py line naming \k for hop-off is now stale.

4. SEED

flake.nix
scripts/boot_menu.py
init.lua
! set -o pipefail; LD_LIBRARY_PATH= nix eval --no-eval-cache --raw .#devShells.x86_64-linux.quiet.shellHook | bash -n && echo "hook parses"
! LD_LIBRARY_PATH= nix eval --no-eval-cache --raw .#devShells.x86_64-linux.quiet.shellHook | rg -n '^\s*(alias (h|p)=|unalias |(p|pr|pro|prom|promp|promt|prompt|x|con|cont|conte|contex|c|com|comp|compi|compil)\(\) )'
! rg -n '^\s*(p|c|h|x) = |alias (p|c|h|x)=' ~/repos/nixos/configuration.nix ~/.bashrc
! rg -n -g '*.md' -g '*.py' -g '*.lua' 'leader>k|\\k\b'

5. CLOSING

The loop has always been three words: say what you want, choose what the AI sees, and build it. This ride made those words cost less to say. A finger can stop at any letter and still land, and the letter that used to mean “go home” became h, which works whatever the install folder is called.

The defensive line added “just in case” turned out to guard against two real aliases already on the machine. The automated instrument meant to prove the change broke for an unrelated reason. The deciding witness was the operator typing one letter, c, and watching a compile run where a directory change would have happened before. Receipts beat recollection, and sometimes the cheapest receipt is a human keystroke whose two possible outcomes look nothing alike.

Sealing the Cartridge and Archival Finality

6. NOTARIZE

  • Byte count: this Manifest carries no wc -c line. The nearest byte measure is the Summary: Total Bytes 293,362 (UTF-8), Verified Tokens 73,923.
  • Receipt count: 5 live command receipts.
  • Newest receipt date: receipts carry no timestamps. The payload’s dated anchor is 2026-10-01, from the LADDERS comment and the session date.
  • Deed: the seal footer names the archive directly. That name is consistent with cartridge 1753, which the operator’s c witness wrote one compile earlier. Verify it with python scripts/foo_cartridge.py qamy.ai_1754-db104144.zip.
Deed: qamy.ai_1754-db104144.zip (ls -t qamy.ai_*.zip head -1)

Book Analysis

Ai Editorial Take

What stands out most here is the conceptual introduction of ‘prefix ladders’ as a form of linguistic tolerance at the Unix boundary. While modern AI models thrive on forgiving, loose natural language, traditional command-line interfaces demand unforgiving syntactic exactness. By treating every prefix as a valid synonym and even catching common typos like ‘promt’, the shell environment begins to exhibit the forgiving ergonomics of a conversational interface without relinquishing the mechanical predictability and speed of native POSIX binaries.

🐦 X.com Promo Tweet

Why type full words when one letter does the job? How prefix ladders and defensive unalias guards create lightning-fast, checkable human-AI iteration loops in Nix:

https://mikelev.in/futureproof/prefix-ladders-and-the-unalias-guard/

#DevOps #NixOS #Linux

Title Brainstorm

  • Title Option: The Prefix Ladder and the Unalias Guard: Replayable Shell Ergonomics in the Age of AI
    • Filename: prefix-ladders-and-the-unalias-guard.md
    • Rationale: Directly names both the ergonomic breakthrough (prefix truncation ladders) and the crucial architectural safeguard (the unalias line preventing bash function syntax crashes), grounding the post in practical, reproducible CLI design.
  • Title Option: Single-Letter Command Ladders: Building Checkable Shell Ergonomics for AI Workflows
    • Filename: single-letter-command-ladders-shell-ergonomics.md
    • Rationale: Highlights the reduction of cognitive and physical typing friction to single characters (p, x, c) while keeping the full continuum of abbreviations functional and checkable.
  • Title Option: The Unalias Guard: Defending Replayable CLI Short-Words Against Shell Drift
    • Filename: unalias-guard-protecting-replayable-cli-short-words.md
    • Rationale: Focuses on the defensive systems engineering aspect: why unalias guards are essential in reproducible dev shells to stop parent-environment aliases from sabotaging function declarations.
  • Title Option: From Whole Words to Single Keystrokes: Tuning the Human-AI Feedback Loop
    • Filename: whole-words-to-single-keystrokes-ai-feedback-loop.md
    • Rationale: Emphasizes the human ergonomics and speed of iteration, viewing shell command optimization as a high-leverage way to keep developers in flow state.

Content Potential And Polish

  • Core Strengths:
    • Identifies and solves a subtle, high-impact Bash quirk: alias expansion inside function definitions breaking devShell initialization.
    • Demonstrates pragmatic design by shadowing rarely used utilities like coreutils ‘pr’ safely inside the subshell while keeping ‘command pr’ reachable.
    • Highlights the value of empirical, human-in-the-loop receipts where a single keystroke (‘c’) cleanly verifies that function definitions override conflicting host aliases.
    • Maintains rigorous dismount discipline with the Notary Beat, capturing unbanked items, ignition status, and exact archive fingerprints.
  • Suggestions For Polish:
    • Harden the Nix evaluation probes by including ‘–no-eval-cache’ and setting ‘pipefail’ so probe failures cannot be masked by bash syntax checks.
    • Document a migration path for parent shell configurations (~/.bashrc or configuration.nix) to align global aliases with devShell conventions and avoid dual-meaning muscle memory.
    • Clarify how the boot menu’s plain-words rule should adapt to single-letter mnemonics (p, x, c, h) without confusing onboarding documentation.

Next Step Prompts

  • Diagnose and resolve the Nix evaluation cache error in probe 2 by testing devShell evaluation with ‘–no-eval-cache’ and configuring ‘set -o pipefail’.
  • Draft an update for ‘scripts/boot_menu.py’ that reconciles the plain-word display policy with the new single-letter command shortcuts.