pipulate 2.66__tar.gz → 2.68__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {pipulate-2.66 → pipulate-2.68}/.agents/skills/journal/references/index.md +3 -2
  2. pipulate-2.68/.agents/skills/pipulate/SKILL.md +153 -0
  3. {pipulate-2.66 → pipulate-2.68}/AGENTS.md +18 -6
  4. {pipulate-2.66 → pipulate-2.68}/PKG-INFO +5 -6
  5. {pipulate-2.66 → pipulate-2.68}/README.md +4 -5
  6. {pipulate-2.66 → pipulate-2.68}/__init__.py +2 -2
  7. {pipulate-2.66 → pipulate-2.68}/pipulate.egg-info/PKG-INFO +5 -6
  8. {pipulate-2.66 → pipulate-2.68}/pipulate.egg-info/SOURCES.txt +1 -0
  9. {pipulate-2.66 → pipulate-2.68}/pyproject.toml +1 -1
  10. {pipulate-2.66 → pipulate-2.68}/.agents/skills/gsc-readonly/SKILL.md +0 -0
  11. {pipulate-2.66 → pipulate-2.68}/.agents/skills/hello-workflow/SKILL.md +0 -0
  12. {pipulate-2.66 → pipulate-2.68}/.agents/skills/journal/SKILL.md +0 -0
  13. {pipulate-2.66 → pipulate-2.68}/.agents/skills/roles/SKILL.md +0 -0
  14. {pipulate-2.66 → pipulate-2.68}/.agents/skills/sheets-readonly/SKILL.md +0 -0
  15. {pipulate-2.66 → pipulate-2.68}/AUDIT.md +0 -0
  16. {pipulate-2.66 → pipulate-2.68}/LICENSE +0 -0
  17. {pipulate-2.66 → pipulate-2.68}/MANIFEST.in +0 -0
  18. {pipulate-2.66 → pipulate-2.68}/apps/010_introduction.py +0 -0
  19. {pipulate-2.66 → pipulate-2.68}/apps/015_config.py +0 -0
  20. {pipulate-2.66 → pipulate-2.68}/apps/020_profiles.py +0 -0
  21. {pipulate-2.66 → pipulate-2.68}/apps/025_aspect.py +0 -0
  22. {pipulate-2.66 → pipulate-2.68}/apps/030_roles.py +0 -0
  23. {pipulate-2.66 → pipulate-2.68}/apps/040_hello_workflow.py +0 -0
  24. {pipulate-2.66 → pipulate-2.68}/apps/050_documentation.py +0 -0
  25. {pipulate-2.66 → pipulate-2.68}/apps/060_tasks.py +0 -0
  26. {pipulate-2.66 → pipulate-2.68}/apps/070_history.py +0 -0
  27. {pipulate-2.66 → pipulate-2.68}/apps/110_parameter_buster.py +0 -0
  28. {pipulate-2.66 → pipulate-2.68}/apps/120_link_graph.py +0 -0
  29. {pipulate-2.66 → pipulate-2.68}/apps/130_gap_analysis.py +0 -0
  30. {pipulate-2.66 → pipulate-2.68}/apps/200_workflow_genesis.py +0 -0
  31. {pipulate-2.66 → pipulate-2.68}/apps/210_widget_examples.py +0 -0
  32. {pipulate-2.66 → pipulate-2.68}/apps/220_roadmap.py +0 -0
  33. {pipulate-2.66 → pipulate-2.68}/apps/230_dev_assistant.py +0 -0
  34. {pipulate-2.66 → pipulate-2.68}/apps/240_simon_mcp.py +0 -0
  35. {pipulate-2.66 → pipulate-2.68}/apps/300_blank_placeholder.py +0 -0
  36. {pipulate-2.66 → pipulate-2.68}/apps/400_botify_trifecta.py +0 -0
  37. {pipulate-2.66 → pipulate-2.68}/apps/440_browser_automation.py +0 -0
  38. {pipulate-2.66 → pipulate-2.68}/apps/450_stream_simulator.py +0 -0
  39. {pipulate-2.66 → pipulate-2.68}/apps/510_text_field.py +0 -0
  40. {pipulate-2.66 → pipulate-2.68}/apps/520_text_area.py +0 -0
  41. {pipulate-2.66 → pipulate-2.68}/apps/530_dropdown.py +0 -0
  42. {pipulate-2.66 → pipulate-2.68}/apps/540_checkboxes.py +0 -0
  43. {pipulate-2.66 → pipulate-2.68}/apps/550_radios.py +0 -0
  44. {pipulate-2.66 → pipulate-2.68}/apps/560_range.py +0 -0
  45. {pipulate-2.66 → pipulate-2.68}/apps/570_switch.py +0 -0
  46. {pipulate-2.66 → pipulate-2.68}/apps/580_upload.py +0 -0
  47. {pipulate-2.66 → pipulate-2.68}/apps/610_markdown.py +0 -0
  48. {pipulate-2.66 → pipulate-2.68}/apps/620_mermaid.py +0 -0
  49. {pipulate-2.66 → pipulate-2.68}/apps/630_prism.py +0 -0
  50. {pipulate-2.66 → pipulate-2.68}/apps/640_javascript.py +0 -0
  51. {pipulate-2.66 → pipulate-2.68}/apps/710_pandas.py +0 -0
  52. {pipulate-2.66 → pipulate-2.68}/apps/720_rich.py +0 -0
  53. {pipulate-2.66 → pipulate-2.68}/apps/730_matplotlib.py +0 -0
  54. {pipulate-2.66 → pipulate-2.68}/apps/810_webbrowser.py +0 -0
  55. {pipulate-2.66 → pipulate-2.68}/apps/820_selenium.py +0 -0
  56. {pipulate-2.66 → pipulate-2.68}/apps/830_pico_slider.py +0 -0
  57. {pipulate-2.66 → pipulate-2.68}/cli.py +0 -0
  58. {pipulate-2.66 → pipulate-2.68}/config.py +0 -0
  59. {pipulate-2.66 → pipulate-2.68}/imports/__init__.py +0 -0
  60. {pipulate-2.66 → pipulate-2.68}/imports/ai_dictdb.py +0 -0
  61. {pipulate-2.66 → pipulate-2.68}/imports/ai_tool_discovery_simple_parser.py +0 -0
  62. {pipulate-2.66 → pipulate-2.68}/imports/append_only_conversation.py +0 -0
  63. {pipulate-2.66 → pipulate-2.68}/imports/ascii_displays.py +0 -0
  64. {pipulate-2.66 → pipulate-2.68}/imports/botify/__init__.py +0 -0
  65. {pipulate-2.66 → pipulate-2.68}/imports/botify/code_generators.py +0 -0
  66. {pipulate-2.66 → pipulate-2.68}/imports/botify/true_schema_discoverer.py +0 -0
  67. {pipulate-2.66 → pipulate-2.68}/imports/botify_code_generation.py +0 -0
  68. {pipulate-2.66 → pipulate-2.68}/imports/crud.py +0 -0
  69. {pipulate-2.66 → pipulate-2.68}/imports/database_safety_wrapper.py +0 -0
  70. {pipulate-2.66 → pipulate-2.68}/imports/dom_processing/__init__.py +0 -0
  71. {pipulate-2.66 → pipulate-2.68}/imports/dom_processing/ai_dom_beautifier.py +0 -0
  72. {pipulate-2.66 → pipulate-2.68}/imports/dom_processing/enhanced_dom_processor.py +0 -0
  73. {pipulate-2.66 → pipulate-2.68}/imports/durable_backup_system.py +0 -0
  74. {pipulate-2.66 → pipulate-2.68}/imports/mcp_orchestrator.py +0 -0
  75. {pipulate-2.66 → pipulate-2.68}/imports/server_logging.py +0 -0
  76. {pipulate-2.66 → pipulate-2.68}/imports/stream_orchestrator.py +0 -0
  77. {pipulate-2.66 → pipulate-2.68}/imports/voice_synthesis.py +0 -0
  78. {pipulate-2.66 → pipulate-2.68}/pipulate/__init__.py +0 -0
  79. {pipulate-2.66 → pipulate-2.68}/pipulate/core.py +0 -0
  80. {pipulate-2.66 → pipulate-2.68}/pipulate.egg-info/dependency_links.txt +0 -0
  81. {pipulate-2.66 → pipulate-2.68}/pipulate.egg-info/entry_points.txt +0 -0
  82. {pipulate-2.66 → pipulate-2.68}/pipulate.egg-info/requires.txt +0 -0
  83. {pipulate-2.66 → pipulate-2.68}/pipulate.egg-info/top_level.txt +0 -0
  84. {pipulate-2.66 → pipulate-2.68}/server.py +0 -0
  85. {pipulate-2.66 → pipulate-2.68}/setup.cfg +0 -0
  86. {pipulate-2.66 → pipulate-2.68}/tests/test_apply_airlock.py +0 -0
  87. {pipulate-2.66 → pipulate-2.68}/tests/test_mck_rep2.py +0 -0
  88. {pipulate-2.66 → pipulate-2.68}/tools/__init__.py +0 -0
  89. {pipulate-2.66 → pipulate-2.68}/tools/advanced_automation_tools.py +0 -0
  90. {pipulate-2.66 → pipulate-2.68}/tools/botify_tools.py +0 -0
  91. {pipulate-2.66 → pipulate-2.68}/tools/connector_tools.py +0 -0
  92. {pipulate-2.66 → pipulate-2.68}/tools/conversation_tools.py +0 -0
  93. {pipulate-2.66 → pipulate-2.68}/tools/dom_tools.py +0 -0
  94. {pipulate-2.66 → pipulate-2.68}/tools/keychain_tools.py +0 -0
  95. {pipulate-2.66 → pipulate-2.68}/tools/llm_optics.py +0 -0
  96. {pipulate-2.66 → pipulate-2.68}/tools/mcp_tools.py +0 -0
  97. {pipulate-2.66 → pipulate-2.68}/tools/scraper_tools.py +0 -0
  98. {pipulate-2.66 → pipulate-2.68}/tools/system_tools.py +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Auto-generated on 2026-09-28 by `scripts/articles/generate_ai_context.py` and
4
4
  > rewritten from scratch on every release. If this date looks stale, assume
5
- > the rest of the repo is newer than this map. 1499 entries indexed.
5
+ > the rest of the repo is newer than this map. 1500 entries indexed.
6
6
 
7
7
  This repository holds the *machinery*. The *reasoning*, the running journal
8
8
  that explains why every piece exists, lives on a separate website and not in
@@ -27,6 +27,7 @@ The first 20 entries include full `index.md` URLs to establish
27
27
  the link pattern. All remaining entries are bare slugs. Reconstruct any full
28
28
  URL as: `https://mikelev.in/futureproof/{slug}/index.md`
29
29
 
30
+ - [2026-09-28] [AGENTS.md and Agent Skills: Refactoring Pipulate for a Checkable PyPI Release](https://mikelev.in/futureproof/agents-md-agent-skills-pypi-receipts/index.md)
30
31
  - [2026-09-28] [The Cost of Forgetting: The Epistemic Price List and the Art of the Lean Codebase](https://mikelev.in/futureproof/the-forgetting-kata-and-the-epistemic-price-list/index.md)
31
32
  - [2026-09-28] [Pinball, Pachinko, and the Art of Replayable AI Workflows](https://mikelev.in/futureproof/pinball-pachinko-replayable-ai-workflows/index.md)
32
33
  - [2026-09-28] [The Three-Folder Boundary: Ergonomic Workspaces and the Blank Stare in the Age of AI](https://mikelev.in/futureproof/three-folder-boundary-and-the-blank-stare/index.md)
@@ -46,12 +47,12 @@ URL as: `https://mikelev.in/futureproof/{slug}/index.md`
46
47
  - [2026-09-18] [The First Ten Minutes: Engineering Reproducible AI Workflows in the Age of AI](https://mikelev.in/futureproof/the-first-ten-minutes-reproducible-ai-workflows/index.md)
47
48
  - [2026-09-17] [The Retrieval Cue: Memory Consolidation and Selective Hydration in the Age of AI](https://mikelev.in/futureproof/retrieval-cue-memory-consolidation-selective-hydration/index.md)
48
49
  - [2026-09-17] [The Voice Asks First: Engineering Verifiable Consent and Silent Defaults](https://mikelev.in/futureproof/the-voice-asks-first-verifiable-consent/index.md)
49
- - [2026-09-17] [The Workbench Pin and the Help Screen Census: Verifiable Receipts in the Age of AI](https://mikelev.in/futureproof/the-workbench-pin-and-the-help-screen-census/index.md)
50
50
 
51
51
  ## Compact slug index — pattern: https://mikelev.in/futureproof/{slug}/index.md
52
52
 
53
53
  Format: `[date] [size] slug` — fetch any entry as `https://mikelev.in/futureproof/{slug}/index.md`
54
54
 
55
+ - [2026-09-17] [122k] the-workbench-pin-and-the-help-screen-census
55
56
  - [2026-09-17] [54k] useless-machine-oauth-replayable-workflows
56
57
  - [2026-09-17] [89k] escaped-monopolies-and-replayable-receipts
57
58
  - [2026-09-17] [149k] ratcheting-wins-in-the-age-of-ai
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: pipulate
3
+ description: Installing Pipulate, the local-first context compiler, on a machine that does not have it, without taking the keyboard away from the person who owns the machine. Use when someone asks to install, start, stop, reset or remove Pipulate, or asks what the one-line installer will do before running it. Read the installer before running it, run the copy you read, and keep every step a command the human types.
4
+ ---
5
+
6
+ # pipulate: install it without giving up the keyboard
7
+
8
+ The skill you keep is the one you can still use when the wrapper is gone.
9
+ Every step below is a command the human types and reads before it runs, so
10
+ the person doing it learns what their machine is doing instead of watching
11
+ a spinner.
12
+
13
+ Two doors serve one installer. `https://pipulate.com/install.sh` lands the
14
+ workshop in `~/pipulate`; `https://npvg.org` serves the same script to `curl`
15
+ with its default folder stamped to `~/npvg` (a browser at that address gets a
16
+ web page instead). The lines below use the npvg door; swap the URL and the
17
+ folder name for the other.
18
+
19
+ ## 1. Look before you run
20
+
21
+ ~~~bash
22
+ curl -fsSL https://npvg.org | less
23
+ ~~~
24
+
25
+ Nothing runs. What appears is the installer as text: a comment block that
26
+ explains the design (a ZIP download and a read-only deploy key, then
27
+ `nix develop`, which turns the folder into a git checkout that updates
28
+ itself), then `main() {`, the whole body inside that function, and a last
29
+ line that calls it. `j` moves down, `k` up, `/nix` searches, `q` quits. The
30
+ function wrapper is deliberate: a download cut off partway cannot run half
31
+ an install.
32
+
33
+ ## 2. Save it, read it, run the copy you read
34
+
35
+ ~~~bash
36
+ curl -fsSL https://npvg.org -o install.sh
37
+ less install.sh
38
+ bash install.sh
39
+ ~~~
40
+
41
+ The file read is the file run, byte for byte; that is the one thing the pipe
42
+ form skips. `bash install.sh myname` puts the workshop in `~/myname` and
43
+ names the app after it; with no argument the folder is the door's default.
44
+
45
+ ## 3. The one line, once you have read it
46
+
47
+ ~~~bash
48
+ curl -fsSL https://npvg.org | bash
49
+ ~~~
50
+
51
+ What it does, in order (the script's own sequence; read it there):
52
+
53
+ 1. Refuses to run under a shell that is not bash, prints one line naming the
54
+ folder and the command that removes it, and stops if `curl` or `unzip`
55
+ is missing.
56
+ 2. If `nix` is missing, runs the Determinate Systems Nix installer and then
57
+ STOPS: close this terminal, open a new one, run the line it prints. That
58
+ stop is expected, not a failure. The line it prints goes through
59
+ pipulate.com and, from the npvg door, carries the folder as an argument
60
+ (`bash -s npvg`), so the app is then named after the folder; the plain
61
+ npvg line names no folder and leaves the app named Pipulate.
62
+ 3. Refuses if the target folder already exists. It never overwrites.
63
+ 4. Downloads the repository as a ZIP from GitHub and unpacks it into the
64
+ folder.
65
+ 5. Fetches a ROT13-encoded deploy key into `.ssh/rot` inside the folder. It
66
+ is pull-only: it lets the folder fetch updates without a GitHub account.
67
+ 6. Writes a `run` file the flake deletes on its first entry (a leftover the
68
+ repo has marked for removal), prints the come-back line, and hands off
69
+ to `nix develop -L`. The first entry can take several minutes while
70
+ packages download; the installer's last line says so, and a long wait
71
+ after it is that download.
72
+
73
+ Inside `nix develop` the flake finishes the job: it clones the repository
74
+ over the ZIP so the folder becomes a real git checkout (the pre-transform
75
+ files are backed up to a temp directory and the path is printed), creates
76
+ `.venv`, installs the Python packages with `uv`, and prints one line of
77
+ readings (Nix version, Python version, Pipulate version, the folder)
78
+ followed by a short list of words to type.
79
+
80
+ ## 4. Three ways in, after that
81
+
82
+ - `cd ~/npvg && nix develop` is the everyday door. On a terminal it stops at
83
+ the short command list and a `(nix)` prompt; nothing has started. Every
84
+ entry also pulls the latest commit, fast-forward only; a local change
85
+ pauses the update and says so.
86
+ - `jn` starts JupyterLab at `http://localhost:8888` with the Onboarding
87
+ notebook open and the app at `http://localhost:5001`, and prints the
88
+ banner. Finishing that notebook is what unlocks the app tab on later
89
+ starts. Ctrl+C stops the app; `pu` starts it again and is also the
90
+ restart word. JupyterLab runs in a `tmux` session named `jupyter` and
91
+ keeps running after the shell is left.
92
+ - `walk` is the first word to type: a guided walk over three public pages
93
+ that teaches the loop. On its first run it shows a card asking whether it
94
+ may read aloud and records the answer; it stays silent until that answer
95
+ is yes, and `voice` changes it later. `menu` reprints the short list,
96
+ `all` the long one, `about` the workspace tree, the three tiers and how
97
+ to check what an AI said against what it was handed. `exit` leaves the
98
+ shell.
99
+
100
+ ## 5. What stays on the machine, and what leaves it
101
+
102
+ Stays: everything runs on localhost, ports 5001 and 8888. The folder holds
103
+ the code, `.venv`, the SQLite databases under `data/`, and the person's own
104
+ notebooks and files under `Workshop/personal/`, which git never tracks.
105
+ Outside the folder, three homes: `~/.config/pipulate/` (settings,
106
+ credentials the person adds by hand, the one-line answer to the voice
107
+ question), `~/.local/share/pipulate/` (two sound files) and
108
+ `~/.local/state/pipulate/` (the compile's own state: `context.txt` when
109
+ `PIPULATE_ADHOC_FILE` points there, and what a move sets aside under
110
+ `stale/`). The browser lanes may leave a driver cache under `~/.cache`; that
111
+ path was not read for this skill. The voice model lands inside the folder,
112
+ under `assets/piper_models/` (gitignored, so removing the folder removes
113
+ it), fetched on the first spoken line after the yes at the voice card.
114
+
115
+ Leaves, as the installer and the flake spell it: GitHub (the ZIP, then the
116
+ clone, then a `git pull` on every `nix develop`); pipulate.com (the deploy
117
+ key, from either door);
118
+ install.determinate.systems, only when Nix is missing; the Nix binary cache
119
+ and PyPI, for packages; Hugging Face once, for a small voice model, and only
120
+ after the person has answered yes at the voice card. No connector calls any
121
+ service until the person warms a credential for it themselves.
122
+
123
+ Two things it touches outside the folder, worth saying out loud: if
124
+ `~/.ssh/id_rsa` does not exist, the flake writes the decoded deploy key
125
+ there and adds a `Host github.com` block to `~/.ssh/config`; an existing key
126
+ is left alone. And Nix is a system-level install with its own uninstaller;
127
+ removing the folder does not remove Nix.
128
+
129
+ ## 6. Stop, reset, remove
130
+
131
+ - Stop the app: Ctrl+C in the window running it. Stop JupyterLab:
132
+ `tmux kill-session -t jupyter`. Leave the shell: `exit`.
133
+ - Reset the Python environment and nothing else: `rm -rf ~/npvg/.venv`, then
134
+ `nix develop` rebuilds it.
135
+ - Remove: `rm -rf ~/npvg` (the installer prints this line itself), then
136
+ `rm -rf ~/.config/pipulate ~/.local/share/pipulate ~/.local/state/pipulate`
137
+ for the three homes outside the folder. If the flake wrote `~/.ssh/id_rsa`
138
+ (the person had
139
+ none before), that key and the `github.com` block in `~/.ssh/config` are
140
+ theirs to remove. Nix stays unless its own uninstaller is run.
141
+
142
+ ## What this skill does not do
143
+
144
+ - It never runs the installer on the person's behalf; it hands them the
145
+ line and reads the script with them.
146
+ - It never edits files in the workshop by hand. Edits go through the
147
+ protocol `AGENTS.md` names: SEARCH/REPLACE blocks, matched exactly once,
148
+ applied by `apply.py`, which checks Python, Nix and JSON syntax before it
149
+ writes. That protocol is always-on in `AGENTS.md` rather than a skill,
150
+ because a skill loads on demand and the protocol is every turn.
151
+ - It was read against four sources: the installer's own text, the door page
152
+ a browser gets at npvg.org, README's Quick Start and AUDIT.md; where the
153
+ installer's text and a page disagreed, the installer's text won.
@@ -1,13 +1,25 @@
1
1
  # AGENTS.md — Pipulate
2
2
 
3
- This repo predates the AGENTS.md / Agent Skills / OKF conventions and complies
4
- with them by *pointing*, not duplicating. The sources of truth here are
5
- executable, so this file is a signpost. Do not add sibling status .md files;
6
- anything written here that duplicates code will drift and is a bug.
3
+ This repository carries Agent Skills under https://agentskills.io/specification
4
+ (`.agents/skills/*/SKILL.md`, a YAML head over a Markdown body, loaded on
5
+ demand), with this file as the nearest-ancestor signpost that points at
6
+ executable truth instead of duplicating it. Every tool call taught here runs
7
+ on localhost under the POSIX conventions of a command, stdin, stdout and an
8
+ exit code, so that its output lands in the sealed compile (`foo.zip`) as a
9
+ receipt; a cloud-side tool call that cannot be reconstructed here is
10
+ non-reproducible, non-portable, cannot be compiled into a cartridge, and is
11
+ out of scope by that rule, not by taste.
12
+
13
+ This repo predates those conventions and complies with them by *pointing*,
14
+ not duplicating. Do not add sibling status .md files; anything written here
15
+ that duplicates code will drift and is a bug.
7
16
 
8
17
  ## Setup (the executable version of "Dev environment tips")
9
18
 
10
- - `nix develop` — full environment (server + JupyterLab). See `flake.nix`.
19
+ - `nix develop` — the full environment. On a terminal it stops at a short
20
+ list of words and a `(nix)` prompt with nothing started; `jn` starts
21
+ JupyterLab and the server. Without a terminal it starts the app, so an
22
+ agent takes the quiet shell below. See `flake.nix`.
11
23
  - `nix develop .#quiet` — minimal shell for agents and scripting.
12
24
  - Python lives in `.venv/`; invoke as `.venv/bin/python`.
13
25
 
@@ -36,7 +48,7 @@ run since the sentinels landed.
36
48
 
37
49
  - Discover: `.venv/bin/python cli.py mcp-discover`
38
50
  - Execute: `.venv/bin/python cli.py call <tool_name> --json-args '{...}'`
39
- - Skills (Agent Skills spec, https://agentskills.io/specification): `.agents/skills/*/SKILL.md`, at the repo root beside this file
51
+ - Skills (Agent Skills spec, https://agentskills.io/specification): `.agents/skills/*/SKILL.md`, at the repo root beside this file; `.claude/skills` is a symlink to the same folder, so Claude Code's project-skills path offers the same skills
40
52
  - The reasoning behind any piece of the machinery: the `journal` skill, whose `references/index.md` lists every journal entry newest first with a fetchable URL
41
53
 
42
54
  ## Context (how this repo talks to AI)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pipulate
3
- Version: 2.66
3
+ Version: 2.68
4
4
  Summary: The context compiler that helps you prompt well — local-first, Nix-reproducible, replayable. The successor to AI SEO software.
5
5
  Author-email: Mike Levin <pipulate@gmail.com>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -101,7 +101,7 @@ cd ~/pipulate && nix develop
101
101
 
102
102
  **What you get:** A local web app at `http://localhost:5001` with step-by-step workflows, integrated AI chat, and a JupyterLab instance at `http://localhost:8888`. No cloud required.
103
103
 
104
- **Success looks like:** A one-line environment reading, then a three-door menu. Press `1` to start JupyterLab and the app server (`2` gives you a bare shell with nothing running; `3` starts both but opens the Pipulate app tab instead). The JupyterLab tab opens in your browser; run the Onboarding notebook top-to-bottom to unlock the Pipulate app (it opens automatically on future launches).
104
+ **Success looks like:** A one-line environment reading, then a short list of words and a `(nix)` prompt. Nothing has started yet. Type `walk` for the guided tour, or `jn` to start JupyterLab and the app server; the JupyterLab tab opens in your browser with the Onboarding notebook, and running it top-to-bottom unlocks the Pipulate app (it opens automatically on future launches).
105
105
 
106
106
  These few commands:
107
107
  - ✅ Updates to the latest version automatically
@@ -614,14 +614,13 @@ cd ~/TestProject
614
614
  nix develop
615
615
  ```
616
616
 
617
- Press `1` at the three-door menu, wait for the JupyterLab tab to open, then run the Onboarding notebook to unlock the Pipulate app.
617
+ Type `jn` at the `(nix)` prompt, wait for the JupyterLab tab to open, then run the Onboarding notebook to unlock the Pipulate app.
618
618
 
619
- **Automating past the boot menu:** `nix develop` ends at a three-door prompt — start with the JupyterLab tab, drop to the shell, or start with the Pipulate tab in front. It fails open, so anything without a terminal (CI, a provisioning script, an SSH session with no tty) starts the app and never sees the prompt. Two environment variables cover the cases that do:
619
+ **Automating past the command list:** on a terminal, `nix develop` ends at a short list of words and a `(nix)` prompt with nothing started; `scripts/boot_menu.py` prints the list, speaks through its exit code and reads no keys. It fails open, so anything without a terminal (CI, a provisioning script, an SSH session with no tty) starts the app and never sees the list. One environment variable covers a terminal that should do the same:
620
620
 
621
621
  | Variable | Effect |
622
622
  |----------|--------|
623
- | `PIPULATE_BOOT_MENU=0` | Skip the prompt entirely and start the app, e.g. `PIPULATE_BOOT_MENU=0 nix develop`. For an unattended terminal that would otherwise wait for a keypress that never comes. |
624
- | `PIPULATE_BOOT_MENU_TIMEOUT=10` | Keep the prompt, but start the app after N seconds if nobody chooses. Off by default — with a human provably present, the prompt waits indefinitely rather than starting something they didn't ask for. |
623
+ | `PIPULATE_BOOT_MENU=0` | Skip the list and start the app, e.g. `PIPULATE_BOOT_MENU=0 nix develop`. For an unattended terminal (one a script types into) that should behave as if it had no tty. |
625
624
 
626
625
  ### 🚨 Installation Troubleshooting
627
626
 
@@ -44,7 +44,7 @@ cd ~/pipulate && nix develop
44
44
 
45
45
  **What you get:** A local web app at `http://localhost:5001` with step-by-step workflows, integrated AI chat, and a JupyterLab instance at `http://localhost:8888`. No cloud required.
46
46
 
47
- **Success looks like:** A one-line environment reading, then a three-door menu. Press `1` to start JupyterLab and the app server (`2` gives you a bare shell with nothing running; `3` starts both but opens the Pipulate app tab instead). The JupyterLab tab opens in your browser; run the Onboarding notebook top-to-bottom to unlock the Pipulate app (it opens automatically on future launches).
47
+ **Success looks like:** A one-line environment reading, then a short list of words and a `(nix)` prompt. Nothing has started yet. Type `walk` for the guided tour, or `jn` to start JupyterLab and the app server; the JupyterLab tab opens in your browser with the Onboarding notebook, and running it top-to-bottom unlocks the Pipulate app (it opens automatically on future launches).
48
48
 
49
49
  These few commands:
50
50
  - ✅ Updates to the latest version automatically
@@ -557,14 +557,13 @@ cd ~/TestProject
557
557
  nix develop
558
558
  ```
559
559
 
560
- Press `1` at the three-door menu, wait for the JupyterLab tab to open, then run the Onboarding notebook to unlock the Pipulate app.
560
+ Type `jn` at the `(nix)` prompt, wait for the JupyterLab tab to open, then run the Onboarding notebook to unlock the Pipulate app.
561
561
 
562
- **Automating past the boot menu:** `nix develop` ends at a three-door prompt — start with the JupyterLab tab, drop to the shell, or start with the Pipulate tab in front. It fails open, so anything without a terminal (CI, a provisioning script, an SSH session with no tty) starts the app and never sees the prompt. Two environment variables cover the cases that do:
562
+ **Automating past the command list:** on a terminal, `nix develop` ends at a short list of words and a `(nix)` prompt with nothing started; `scripts/boot_menu.py` prints the list, speaks through its exit code and reads no keys. It fails open, so anything without a terminal (CI, a provisioning script, an SSH session with no tty) starts the app and never sees the list. One environment variable covers a terminal that should do the same:
563
563
 
564
564
  | Variable | Effect |
565
565
  |----------|--------|
566
- | `PIPULATE_BOOT_MENU=0` | Skip the prompt entirely and start the app, e.g. `PIPULATE_BOOT_MENU=0 nix develop`. For an unattended terminal that would otherwise wait for a keypress that never comes. |
567
- | `PIPULATE_BOOT_MENU_TIMEOUT=10` | Keep the prompt, but start the app after N seconds if nobody chooses. Off by default — with a human provably present, the prompt waits indefinitely rather than starting something they didn't ask for. |
566
+ | `PIPULATE_BOOT_MENU=0` | Skip the list and start the app, e.g. `PIPULATE_BOOT_MENU=0 nix develop`. For an unattended terminal (one a script types into) that should behave as if it had no tty. |
568
567
 
569
568
  ### 🚨 Installation Troubleshooting
570
569
 
@@ -12,7 +12,7 @@ Usage:
12
12
  pipulate
13
13
  """
14
14
 
15
- __version__ = "2.66"
15
+ __version__ = "2.68"
16
16
  # APOSTROPHES RESTORED (2026-08-04). They were stripped as a workaround for
17
17
  # flake.nix's descMatch regex, whose character class excluded ' from the
18
18
  # CAPTURE and truncated the banner to "(So)". That regex was fixed in the same
@@ -23,7 +23,7 @@ __version__ = "2.66"
23
23
  # is not a property of the system; the regex is. Blast radius is one banner:
24
24
  # nothing but flake.nix reads this name -- version_sync.py syncs __version__
25
25
  # and __description__, never this. So'wI' chu' -- "engage the cloaking device."
26
- __version_description__ = "Convention Convention"
26
+ __version_description__ = "Pipulate Claude Skill Banked"
27
27
  # SPDX expression, single source of truth, synced into pyproject.toml by
28
28
  # scripts/release/version_sync.py. "-or-later" (not bare AGPL-3.0, which is
29
29
  # deprecated SPDX) because the header below grants "any later version".
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pipulate
3
- Version: 2.66
3
+ Version: 2.68
4
4
  Summary: The context compiler that helps you prompt well — local-first, Nix-reproducible, replayable. The successor to AI SEO software.
5
5
  Author-email: Mike Levin <pipulate@gmail.com>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -101,7 +101,7 @@ cd ~/pipulate && nix develop
101
101
 
102
102
  **What you get:** A local web app at `http://localhost:5001` with step-by-step workflows, integrated AI chat, and a JupyterLab instance at `http://localhost:8888`. No cloud required.
103
103
 
104
- **Success looks like:** A one-line environment reading, then a three-door menu. Press `1` to start JupyterLab and the app server (`2` gives you a bare shell with nothing running; `3` starts both but opens the Pipulate app tab instead). The JupyterLab tab opens in your browser; run the Onboarding notebook top-to-bottom to unlock the Pipulate app (it opens automatically on future launches).
104
+ **Success looks like:** A one-line environment reading, then a short list of words and a `(nix)` prompt. Nothing has started yet. Type `walk` for the guided tour, or `jn` to start JupyterLab and the app server; the JupyterLab tab opens in your browser with the Onboarding notebook, and running it top-to-bottom unlocks the Pipulate app (it opens automatically on future launches).
105
105
 
106
106
  These few commands:
107
107
  - ✅ Updates to the latest version automatically
@@ -614,14 +614,13 @@ cd ~/TestProject
614
614
  nix develop
615
615
  ```
616
616
 
617
- Press `1` at the three-door menu, wait for the JupyterLab tab to open, then run the Onboarding notebook to unlock the Pipulate app.
617
+ Type `jn` at the `(nix)` prompt, wait for the JupyterLab tab to open, then run the Onboarding notebook to unlock the Pipulate app.
618
618
 
619
- **Automating past the boot menu:** `nix develop` ends at a three-door prompt — start with the JupyterLab tab, drop to the shell, or start with the Pipulate tab in front. It fails open, so anything without a terminal (CI, a provisioning script, an SSH session with no tty) starts the app and never sees the prompt. Two environment variables cover the cases that do:
619
+ **Automating past the command list:** on a terminal, `nix develop` ends at a short list of words and a `(nix)` prompt with nothing started; `scripts/boot_menu.py` prints the list, speaks through its exit code and reads no keys. It fails open, so anything without a terminal (CI, a provisioning script, an SSH session with no tty) starts the app and never sees the list. One environment variable covers a terminal that should do the same:
620
620
 
621
621
  | Variable | Effect |
622
622
  |----------|--------|
623
- | `PIPULATE_BOOT_MENU=0` | Skip the prompt entirely and start the app, e.g. `PIPULATE_BOOT_MENU=0 nix develop`. For an unattended terminal that would otherwise wait for a keypress that never comes. |
624
- | `PIPULATE_BOOT_MENU_TIMEOUT=10` | Keep the prompt, but start the app after N seconds if nobody chooses. Off by default — with a human provably present, the prompt waits indefinitely rather than starting something they didn't ask for. |
623
+ | `PIPULATE_BOOT_MENU=0` | Skip the list and start the app, e.g. `PIPULATE_BOOT_MENU=0 nix develop`. For an unattended terminal (one a script types into) that should behave as if it had no tty. |
625
624
 
626
625
  ### 🚨 Installation Troubleshooting
627
626
 
@@ -12,6 +12,7 @@ server.py
12
12
  .agents/skills/hello-workflow/SKILL.md
13
13
  .agents/skills/journal/SKILL.md
14
14
  .agents/skills/journal/references/index.md
15
+ .agents/skills/pipulate/SKILL.md
15
16
  .agents/skills/roles/SKILL.md
16
17
  .agents/skills/sheets-readonly/SKILL.md
17
18
  apps/010_introduction.py
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "pipulate"
7
7
  # VERSION NOTE: Synced from pipulate/__init__.py.__version__ via python version_sync.py
8
- version = "2.66"
8
+ version = "2.68"
9
9
  authors = [
10
10
  { name="Mike Levin", email="pipulate@gmail.com" },
11
11
  ]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes