memstack-skill-loader 4.14.0__tar.gz → 4.15.0__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.

Potentially problematic release.


This version of memstack-skill-loader might be problematic. Click here for more details.

Files changed (74) hide show
  1. memstack_skill_loader-4.15.0/PKG-INFO +276 -0
  2. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/README.md +54 -26
  3. memstack_skill_loader-4.15.0/pyproject.toml +51 -0
  4. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/__init__.py +1 -1
  5. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/agent_runner.py +69 -3
  6. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/categories.py +0 -1
  7. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/config.py +19 -5
  8. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/dashboard.html +150 -6
  9. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/dashboard.py +121 -8
  10. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/diary_ingest.py +42 -2
  11. memstack_skill_loader-4.15.0/src/memstack_skill_loader/hooks/deny_git.py +107 -0
  12. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/hooks/deny_manager_write.py +20 -2
  13. memstack_skill_loader-4.15.0/src/memstack_skill_loader/hooks/deny_reviewer_git.py +49 -0
  14. memstack_skill_loader-4.15.0/src/memstack_skill_loader/hooks/git_policy.py +333 -0
  15. memstack_skill_loader-4.15.0/src/memstack_skill_loader/index_meta.py +487 -0
  16. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/indexer.py +26 -2
  17. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/server.py +123 -17
  18. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/tfidf_search.py +48 -5
  19. memstack_skill_loader-4.15.0/src/memstack_skill_loader.egg-info/PKG-INFO +276 -0
  20. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader.egg-info/SOURCES.txt +8 -1
  21. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader.egg-info/requires.txt +4 -1
  22. memstack_skill_loader-4.15.0/tests/test_dashscan.py +242 -0
  23. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_diary_ingest.py +76 -0
  24. memstack_skill_loader-4.15.0/tests/test_git_policy.py +351 -0
  25. memstack_skill_loader-4.15.0/tests/test_index_meta_guard.py +262 -0
  26. memstack_skill_loader-4.15.0/tests/test_wheel_contents.py +164 -0
  27. memstack_skill_loader-4.14.0/PKG-INFO +0 -11
  28. memstack_skill_loader-4.14.0/pyproject.toml +0 -26
  29. memstack_skill_loader-4.14.0/src/memstack_skill_loader/hooks/deny_git.py +0 -21
  30. memstack_skill_loader-4.14.0/src/memstack_skill_loader.egg-info/PKG-INFO +0 -11
  31. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/MANIFEST.in +0 -0
  32. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/setup.cfg +0 -0
  33. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/__main__.py +0 -0
  34. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/compression.py +0 -0
  35. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/goal.py +0 -0
  36. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/goal_engine.py +0 -0
  37. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/hooks/__init__.py +0 -0
  38. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/license.py +0 -0
  39. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/memory_db.py +0 -0
  40. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/memory_engine.py +0 -0
  41. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/__init__.py +0 -0
  42. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/_diag.py +0 -0
  43. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/body_parser.py +0 -0
  44. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/compressor.py +0 -0
  45. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/forwarder.py +0 -0
  46. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/pro_compressor.py +0 -0
  47. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/server.py +0 -0
  48. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/proxy/stats_tracker.py +0 -0
  49. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/search.py +0 -0
  50. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/session_context.py +0 -0
  51. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/skill_config.py +0 -0
  52. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/skill_descriptions.json +0 -0
  53. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/stats.py +0 -0
  54. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader/version_check.py +0 -0
  55. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader.egg-info/dependency_links.txt +0 -0
  56. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader.egg-info/entry_points.txt +0 -0
  57. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/src/memstack_skill_loader.egg-info/top_level.txt +0 -0
  58. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_advisor_strategy.py +0 -0
  59. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_body_parser_metric.py +0 -0
  60. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_builder_scope.py +0 -0
  61. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_code_read_savings.py +0 -0
  62. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_failed_approaches.py +0 -0
  63. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_license_environment.py +0 -0
  64. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_license_grace.py +0 -0
  65. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_memory_engine.py +0 -0
  66. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_memory_inspector.py +0 -0
  67. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_memory_scoring.py +0 -0
  68. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_memory_tools.py +0 -0
  69. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_pro_compressor.py +0 -0
  70. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_pro_skills_update.py +0 -0
  71. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_project_dir_canonical.py +0 -0
  72. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_search_memory.py +0 -0
  73. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_session_context.py +0 -0
  74. {memstack_skill_loader-4.14.0 → memstack_skill_loader-4.15.0}/tests/test_skill_drift.py +0 -0
@@ -0,0 +1,276 @@
1
+ Metadata-Version: 2.4
2
+ Name: memstack-skill-loader
3
+ Version: 4.15.0
4
+ Summary: MCP server that vector-indexes MemStack Pro skills for on-demand loading
5
+ Project-URL: Homepage, https://memstack.pro
6
+ Project-URL: Documentation, https://memstack.pro/docs
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: mcp<2.0.0,>=1.0.0
10
+ Requires-Dist: lancedb>=0.6.0
11
+ Requires-Dist: sentence-transformers>=2.2.0
12
+ Requires-Dist: pyarrow>=14.0.0
13
+ Requires-Dist: httpx>=0.24.0
14
+ Requires-Dist: aiohttp>=3.9
15
+ Provides-Extra: dev
16
+ Requires-Dist: setuptools>=68; extra == "dev"
17
+
18
+ # MemStack™ Skill Loader
19
+
20
+ **130 skills for Claude Code:** 86 free + 44 Pro exclusive. Vector-indexed so CC loads only the skill it needs, saving your context window.
21
+
22
+ ## Quick Start (5 minutes)
23
+
24
+ MemStack installs in two parts: the **skills** (via the Claude Code plugin marketplace) and the **engine** (this loader, via PyPI). You need both. Every command below is labeled **(in Claude Code)** or **(in terminal)** — running one in the wrong place is the most common setup mistake.
25
+
26
+ **Step 1 — Install the free skills · (in Claude Code):**
27
+ ```
28
+ /plugin marketplace add cwinvestments/memstack
29
+ /plugin install memstack@cwinvestments-memstack
30
+ ```
31
+ Run both commands. This unlocks the 86 free skills right away.
32
+
33
+ > **SSH error?** ("Host key verification failed" on a fresh server that's never used GitHub over SSH.)
34
+ > **Default fix · (in terminal)** — rewrite GitHub to HTTPS, then retry Step 1:
35
+ > ```bash
36
+ > git config --global url."https://github.com/".insteadOf "git@github.com:"
37
+ > ```
38
+ > **Backup fix · (in terminal)** — add GitHub's host key, then retry Step 1:
39
+ > ```bash
40
+ > mkdir -p ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
41
+ > ```
42
+
43
+ **Step 2 — Install the engine · (in terminal):**
44
+
45
+ Windows:
46
+ ```bash
47
+ pip install memstack-skill-loader
48
+ ```
49
+
50
+ Linux / Mac — use the explicit interpreter (the same one you register in Step 3):
51
+ ```bash
52
+ /usr/bin/python3 -m pip install memstack-skill-loader --break-system-packages
53
+ ```
54
+ Find yours with `which python3` and substitute it if it isn't `/usr/bin/python3`. The `--break-system-packages` flag is required on newer externally-managed Python. No pip for that interpreter? Run `sudo apt install python3-pip` first (Debian/Ubuntu).
55
+
56
+ **Step 3 — Register the MCP server · (in terminal):** register against the **same interpreter you installed onto in Step 2.**
57
+
58
+ Windows:
59
+ ```bash
60
+ claude mcp add --scope user memstack-skills -- python -m memstack_skill_loader
61
+ ```
62
+
63
+ Linux / Mac:
64
+ ```bash
65
+ claude mcp add --scope user memstack-skills -- /usr/bin/python3 -m memstack_skill_loader
66
+ ```
67
+ If this doesn't match Step 2's interpreter, the server won't launch (you'll see a "failed to reconnect" error and `activate_license` will be missing).
68
+
69
+ **Step 4 — Activate your license · (in Claude Code, after a full restart):** fully quit and reopen Claude Code first so it picks up the new MCP server, then run:
70
+ ```
71
+ activate_license(key="your-key", email="you@example.com")
72
+ ```
73
+ Use `key="free"` for the free tier, or your Pro key from [memstack.pro](https://memstack.pro) to unlock all 44 Pro skills (86 free + 44 Pro = 130 total). Then type `list skills` to verify.
74
+
75
+ > **The first start is slow, and that is normal.** On the very first run after installing or upgrading, the server builds the skill index before it answers anything. Expect roughly a minute, nearly all of it loading the embedding model rather than reading your skills. **The server will look unresponsive for that time.** Let it finish. Every later start reuses the index and is not affected.
76
+
77
+ > To override the skills path, set `MEMSTACK_SKILLS_DIR=/path/to/your/memstack/skills`.
78
+
79
+ > See [Getting Started](https://memstack.pro/docs/getting-started) for detailed setup and [Skill Reference](https://memstack.pro/docs/skills) for the full skill catalog. If you hit issues, the [Troubleshooting](#troubleshooting) section below covers the common ones.
80
+
81
+ ## Troubleshooting
82
+
83
+ **Nothing responds after a fresh install, and it does not seem to be failing either (during Step 4):** the first start builds the skill index before the server answers anything, which takes roughly a minute. Most of that is loading the embedding model, not reading your skills. There is no progress output, so a working first start and a hung one look identical. Wait it out before changing anything. If it is still silent well past a couple of minutes, then treat it as the interpreter mismatch below. Later starts reuse the index and respond immediately.
84
+
85
+ **`error: externally-managed-environment` (during Step 2)** — pip refuses to install on a system-managed Python. Add `--break-system-packages` · (in terminal):
86
+ ```bash
87
+ /usr/bin/python3 -m pip install memstack-skill-loader --break-system-packages
88
+ ```
89
+
90
+ **Plugin clone fails: "Host key verification failed" (during Step 1)** — a fresh server that's never connected to GitHub over SSH. **Default fix · (in terminal):** `git config --global url."https://github.com/".insteadOf "git@github.com:"` then retry Step 1. **Backup fix · (in terminal):** `mkdir -p ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts` then retry Step 1.
91
+
92
+ **`activate_license` not found, or MCP "failed to reconnect (-32000)"** — the loader was installed onto a **different Python interpreter** than the one Claude Code launches (the classic bare-`python` mismatch on Linux/Mac). Check · (in terminal):
93
+ ```bash
94
+ /usr/bin/python3 -c "import memstack_skill_loader; print('ok')"
95
+ ```
96
+ If it prints `ok`, make sure Step 3 registered that exact path, then fully restart Claude Code. If it errors with `ModuleNotFoundError`, reinstall onto the explicit interpreter and re-register against that same path · (in terminal):
97
+ ```bash
98
+ /usr/bin/python3 -m pip install memstack-skill-loader --break-system-packages
99
+ claude mcp add --scope user memstack-skills -- /usr/bin/python3 -m memstack_skill_loader
100
+ ```
101
+ Then fully restart Claude Code. Rule of thumb: whatever interpreter you `import`-check as `ok` is the path that must appear in your `claude mcp add` command.
102
+
103
+ **`No module named pip` (during Step 2)** — that interpreter ships without pip (common on minimal Debian/Ubuntu server images). Install it, then retry the Step 2 install · (in terminal):
104
+ ```bash
105
+ sudo apt install python3-pip
106
+ ```
107
+
108
+ ## How It Works
109
+
110
+ MCP server that vector-indexes all 130 MemStack™ skills so Claude Code can call `find_skill("deploy to Railway")` and load **only** the relevant skill on demand, instead of all skills consuming context window.
111
+
112
+ - **No Anthropic API key required:** skill search and indexing run locally and never leave your machine. Three small calls happen on their own at session start — license validation, a Pro-bundle version probe, and a PyPI update check — and every other outbound call is one you trigger ([Data and privacy](#data-and-privacy))
113
+ - **Pro skills auto-detected:** once activated, the Pro skills directory is added to your sources automatically, with no `config.json` edit
114
+ - **Auto-reindex on start:** skills stay current without manual rebuilds. Only startup ever rebuilds, never a search. The first start pays a one-time build of roughly a minute; after that a rebuild happens in the background while the existing index keeps serving, so later starts are not delayed
115
+ - **Memory Engine:** an append-only, versioned fact store with query-time recall scoring — facts decay with age and decay more slowly the more they are recalled. Facts flow in from the diary's `## FACTS` block and are exposed to Claude through five `mem_*` tools (see [Available Tools](#available-tools))
116
+ - **Living memory at session start:** the SessionStart hook injects a compact, token-budgeted digest of the project's top recall-scored facts into context. It fails open — a missing, empty, or unreachable store never blocks startup
117
+ - **8-page localhost dashboard:** Overview, Skills Manager, Burn Report, Memory Browser (project-aware diary reader), Memory Inspector (read-only Memory Engine fact views), Agent Monitor, Referrals, and Settings
118
+
119
+ ### Data and privacy
120
+
121
+ Outbound calls fall into two groups: the ones the loader makes on its own, and the ones you trigger. Both are listed in full.
122
+
123
+ **Automatic — these happen at session start without you asking:**
124
+
125
+ - **License validation** → POST to `admin.cwaffiliateinvestments.com/api/licenses/validate`, with:
126
+ - your **license key**
127
+ - a **machine ID** — a stable, hashed fingerprint that binds the license to your machine
128
+ - your **email**, if you provided one at activation
129
+ - your **environment** — OS name, Python version, and MemStack loader version
130
+
131
+ That is the complete payload.
132
+ - **Pro bundle version probe** → GET to `admin.cwaffiliateinvestments.com/api/skills/pro-bundle/version`. Pro licenses only, at most once every 24 hours. Sends your license key as a bearer token and nothing else; it asks only whether a newer skill bundle exists.
133
+ - **Update check** → GET to `pypi.org/pypi/memstack-skill-loader/json`. At most once every 24 hours. Sends no payload at all — it reads the latest published version number so the loader can tell you an upgrade is available.
134
+
135
+ **Triggered by you — these never fire on their own:**
136
+
137
+ - **Pro skills download** → GET to `admin.cwaffiliateinvestments.com/api/skills/pro-bundle`, when you run `activate_license` or `refresh_pro_skills`, and when the version probe above finds a newer bundle. Sends your license key.
138
+ - **Agent Runner** → `api.anthropic.com`, only while you are running an agent. This is the one call that carries your actual work: the task you wrote and the contents of the files the agents read. It uses your own Anthropic API key, and nothing is sent unless you start an agent.
139
+ - **Referrals page** → POST to `memstack.pro/api/referrals/me`, only when you open that dashboard page. Sends your license key.
140
+ - **TokenStack proxy** → `api.anthropic.com`, only if you start the proxy yourself. It forwards your Claude Code traffic after compressing it, and is off unless you turn it on.
141
+
142
+ Outside the Agent Runner and the TokenStack proxy — both of which you start deliberately, and both of which talk to Anthropic rather than to us — **no code, file contents, file paths, usernames, project names, or prompts are ever sent.** The environment fields in license validation exist only so platform-specific breakage (for example, a bug that affects only Linux) is visible to us in aggregate.
143
+
144
+ ### Environment Variable Override
145
+
146
+ Set `MEMSTACK_SKILLS_DIR` to override the skills path in `config.json`:
147
+
148
+ ```bash
149
+ export MEMSTACK_SKILLS_DIR=/path/to/your/memstack/skills
150
+ ```
151
+
152
+ ## Stack
153
+
154
+ - Python 3.10+
155
+ - [MCP SDK](https://pypi.org/project/mcp/) (stdio transport)
156
+ - [LanceDB](https://lancedb.com/) (vector storage, zero external dependencies)
157
+ - [sentence-transformers](https://www.sbert.net/) with `all-MiniLM-L6-v2` (384-dim local embeddings)
158
+
159
+ ## Available Tools
160
+
161
+ ### `find_skill`
162
+ Search skills by describing what you need. Returns the most relevant skill(s) with full instructions.
163
+
164
+ ```
165
+ find_skill(query="deploy to Railway", top_k=3)
166
+ ```
167
+
168
+ ### `list_skills`
169
+ Browse the full skill catalog with names and descriptions.
170
+
171
+ ```
172
+ list_skills()
173
+ ```
174
+
175
+ ### `get_skill`
176
+ Load a specific skill by exact name.
177
+
178
+ ```
179
+ get_skill(name="railway deploy")
180
+ ```
181
+
182
+ ### `reindex_skills`
183
+ Rebuild the vector index after adding or modifying skills.
184
+
185
+ ```
186
+ reindex_skills()
187
+ ```
188
+
189
+ ### Memory Engine
190
+
191
+ The `mem_*` tools back a persistent, append-only fact store shared across sessions (see [How It Works](#how-it-works)).
192
+
193
+ - **`mem_store`** — Store a new immutable fact (subject, claim, provenance). Returns the fact id and its provenance tag.
194
+ - **`mem_correct`** — Correct a fact by superseding it with a new one. Corrections extend only from the live tip of a chain; correcting a superseded fact is refused and names the current tip.
195
+ - **`mem_recall`** — Recall live facts for a project, each rendered with an inline provenance tag `[method · source · recalled Nx]`. Each returned fact is logged as a recall. Optional full-text query or exact-subject filter.
196
+ - **`mem_inspect`** — Inspect a single fact and its full supersession chain (root → tip) with statuses, provenance, entities, and recall count.
197
+ - **`mem_stats`** — Fact-store statistics: totals by status (live/superseded/retracted), distinct subjects, and recall count. Optionally scoped to a project.
198
+
199
+ ## Configuration
200
+
201
+ The `config.json` file controls where skills are loaded from:
202
+
203
+ ```json
204
+ {
205
+ "skill_sources": [
206
+ {
207
+ "type": "local",
208
+ "path": "/path/to/memstack/skills",
209
+ "pattern": "**/SKILL.md",
210
+ "label": "MemStack"
211
+ }
212
+ ],
213
+ "embedding_model": "all-MiniLM-L6-v2",
214
+ "default_top_k": 3,
215
+ "vector_db_path": "./vectors",
216
+ "auto_reindex_on_start": true
217
+ }
218
+ ```
219
+
220
+ `vector_db_path` sets where the skill index is stored. A relative value resolves against the canonical state root `~/.memstack`, not against the directory holding `config.json`, so the index lives in one place regardless of which directory a process is started from. An absolute or `~`-prefixed value is honored verbatim.
221
+
222
+ You never add Pro skills to `config.json` by hand: the loader adds that directory itself once a key is present. Run `activate_license` at least once regardless, because that is the step that validates your key and downloads the Pro skills. `MEMSTACK_PRO_LICENSE_KEY` is an optional override that supplies the key without storing it, and it takes precedence over the stored one, but on its own it downloads nothing.
223
+
224
+ Add entries to `skill_sources` to index skills from multiple directories:
225
+
226
+ ```json
227
+ {
228
+ "skill_sources": [
229
+ {
230
+ "type": "local",
231
+ "path": "/path/to/memstack/skills",
232
+ "pattern": "**/SKILL.md",
233
+ "label": "MemStack"
234
+ },
235
+ {
236
+ "type": "local",
237
+ "path": "/home/user/custom-skills",
238
+ "pattern": "*.md",
239
+ "label": "My Custom Skills"
240
+ }
241
+ ]
242
+ }
243
+ ```
244
+
245
+ The `pattern` field controls how skills are discovered:
246
+ - `**/SKILL.md`: Subdirectory structure (e.g., `category/skill-name/SKILL.md`)
247
+ - `*.md`: Flat directory (each `.md` file is a skill)
248
+
249
+ ## Release Notes
250
+
251
+ ### 4.15.0 (August 2026)
252
+
253
+ - The skill index moved to the canonical state root, so a relative `vector_db_path` no longer depends on which directory the server happened to start in. **The first start after installing or upgrading rebuilds the index once, which takes roughly a minute**, nearly all of it loading the embedding model. Later starts are unaffected.
254
+ - New index guard classifies the index as current, drift, stale, absent, or rebuilding, and reports that verdict at startup and in the dashboard. Only startup may rebuild on its own, so no search request ever blocks on one.
255
+ - Agent Runner git policy rewritten as an argv-level classifier, replacing a substring match that could not tell `git status` from `git push`.
256
+
257
+ ### 4.10.0 to 4.14.1 (July 2026)
258
+
259
+ - Memory Engine: diary `## FACTS` ingestion, living-memory injection at session start, a read-only Memory Inspector dashboard page, and recall that ranks the whole live fact set rather than a window of it.
260
+ - Added the goal skill, bringing the public catalog to 130 skills (86 free + 44 Pro).
261
+ - Added the video-review Pro skill.
262
+ - Referrals page added to the dashboard.
263
+ - License validation now discloses its full payload in-product (see [Data and privacy](#data-and-privacy)).
264
+ - Packaging fix: `skill_descriptions.json` now ships in the wheel, so a pip install no longer falls back to empty dashboard descriptions.
265
+
266
+ ### 4.0.0 to 4.9.0 (May to July 2026)
267
+
268
+ - Dashboard and Agent Runner: 3-agent orchestration (Manager, Builder, Reviewer) with per-agent model selection, context window monitoring, and token cost tracking.
269
+ - Session diary with markdown narratives, and safe git staging that keeps secrets and runtime data out of commits.
270
+ - TokenStack proxy compression, including AST compression of line-numbered Python.
271
+ - Memory Browser with project filtering and secret masking.
272
+ - Licensing hardened against transient network failures and machine mismatches.
273
+
274
+ ## License
275
+
276
+ Proprietary. Part of MemStack™ Pro by CW Affiliate Investments LLC.
@@ -55,12 +55,16 @@ activate_license(key="your-key", email="you@example.com")
55
55
  ```
56
56
  Use `key="free"` for the free tier, or your Pro key from [memstack.pro](https://memstack.pro) to unlock all 44 Pro skills (86 free + 44 Pro = 130 total). Then type `list skills` to verify.
57
57
 
58
+ > **The first start is slow, and that is normal.** On the very first run after installing or upgrading, the server builds the skill index before it answers anything. Expect roughly a minute, nearly all of it loading the embedding model rather than reading your skills. **The server will look unresponsive for that time.** Let it finish. Every later start reuses the index and is not affected.
59
+
58
60
  > To override the skills path, set `MEMSTACK_SKILLS_DIR=/path/to/your/memstack/skills`.
59
61
 
60
- > See [QUICKSTART.md](QUICKSTART.md) for detailed setup, [QUICK-REFERENCE.md](QUICK-REFERENCE.md) for the full skill catalog, and [TROUBLESHOOTING.md](TROUBLESHOOTING.md) if you hit issues.
62
+ > See [Getting Started](https://memstack.pro/docs/getting-started) for detailed setup and [Skill Reference](https://memstack.pro/docs/skills) for the full skill catalog. If you hit issues, the [Troubleshooting](#troubleshooting) section below covers the common ones.
61
63
 
62
64
  ## Troubleshooting
63
65
 
66
+ **Nothing responds after a fresh install, and it does not seem to be failing either (during Step 4):** the first start builds the skill index before the server answers anything, which takes roughly a minute. Most of that is loading the embedding model, not reading your skills. There is no progress output, so a working first start and a hung one look identical. Wait it out before changing anything. If it is still silent well past a couple of minutes, then treat it as the interpreter mismatch below. Later starts reuse the index and respond immediately.
67
+
64
68
  **`error: externally-managed-environment` (during Step 2)** — pip refuses to install on a system-managed Python. Add `--break-system-packages` · (in terminal):
65
69
  ```bash
66
70
  /usr/bin/python3 -m pip install memstack-skill-loader --break-system-packages
@@ -88,23 +92,37 @@ sudo apt install python3-pip
88
92
 
89
93
  MCP server that vector-indexes all 130 MemStack™ skills so Claude Code can call `find_skill("deploy to Railway")` and load **only** the relevant skill on demand, instead of all skills consuming context window.
90
94
 
91
- - **No Anthropic API key required:** skill search and indexing run locally the only outbound network call is license validation, which contacts the MemStack license server on session start ([Data and privacy](#data-and-privacy))
92
- - **Pro skills auto-detected:** set your license key and they appear automatically
93
- - **Auto-reindex on start:** skills stay current without manual rebuilds
95
+ - **No Anthropic API key required:** skill search and indexing run locally and never leave your machine. Three small calls happen on their own at session start — license validation, a Pro-bundle version probe, and a PyPI update check — and every other outbound call is one you trigger ([Data and privacy](#data-and-privacy))
96
+ - **Pro skills auto-detected:** once activated, the Pro skills directory is added to your sources automatically, with no `config.json` edit
97
+ - **Auto-reindex on start:** skills stay current without manual rebuilds. Only startup ever rebuilds, never a search. The first start pays a one-time build of roughly a minute; after that a rebuild happens in the background while the existing index keeps serving, so later starts are not delayed
94
98
  - **Memory Engine:** an append-only, versioned fact store with query-time recall scoring — facts decay with age and decay more slowly the more they are recalled. Facts flow in from the diary's `## FACTS` block and are exposed to Claude through five `mem_*` tools (see [Available Tools](#available-tools))
95
99
  - **Living memory at session start:** the SessionStart hook injects a compact, token-budgeted digest of the project's top recall-scored facts into context. It fails open — a missing, empty, or unreachable store never blocks startup
96
100
  - **8-page localhost dashboard:** Overview, Skills Manager, Burn Report, Memory Browser (project-aware diary reader), Memory Inspector (read-only Memory Engine fact views), Agent Monitor, Referrals, and Settings
97
101
 
98
102
  ### Data and privacy
99
103
 
100
- License validation is the loader's only outbound network call. On session start it POSTs to the MemStack license server (`admin.cwaffiliateinvestments.com/api/licenses/validate`) with:
104
+ Outbound calls fall into two groups: the ones the loader makes on its own, and the ones you trigger. Both are listed in full.
105
+
106
+ **Automatic — these happen at session start without you asking:**
107
+
108
+ - **License validation** → POST to `admin.cwaffiliateinvestments.com/api/licenses/validate`, with:
109
+ - your **license key**
110
+ - a **machine ID** — a stable, hashed fingerprint that binds the license to your machine
111
+ - your **email**, if you provided one at activation
112
+ - your **environment** — OS name, Python version, and MemStack loader version
113
+
114
+ That is the complete payload.
115
+ - **Pro bundle version probe** → GET to `admin.cwaffiliateinvestments.com/api/skills/pro-bundle/version`. Pro licenses only, at most once every 24 hours. Sends your license key as a bearer token and nothing else; it asks only whether a newer skill bundle exists.
116
+ - **Update check** → GET to `pypi.org/pypi/memstack-skill-loader/json`. At most once every 24 hours. Sends no payload at all — it reads the latest published version number so the loader can tell you an upgrade is available.
101
117
 
102
- - your **license key**
103
- - a **machine ID** — a stable, hashed fingerprint that binds the license to your machine
104
- - your **email**, if you provided one at activation
105
- - your **environment** — OS name, Python version, and MemStack loader version
118
+ **Triggered by you — these never fire on their own:**
106
119
 
107
- That is the complete payload. **No code, file contents, file paths, usernames, project names, or prompts are ever sent.** The environment fields exist only so platform-specific breakage (for example, a bug that affects only Linux) is visible to us in aggregate.
120
+ - **Pro skills download** GET to `admin.cwaffiliateinvestments.com/api/skills/pro-bundle`, when you run `activate_license` or `refresh_pro_skills`, and when the version probe above finds a newer bundle. Sends your license key.
121
+ - **Agent Runner** → `api.anthropic.com`, only while you are running an agent. This is the one call that carries your actual work: the task you wrote and the contents of the files the agents read. It uses your own Anthropic API key, and nothing is sent unless you start an agent.
122
+ - **Referrals page** → POST to `memstack.pro/api/referrals/me`, only when you open that dashboard page. Sends your license key.
123
+ - **TokenStack proxy** → `api.anthropic.com`, only if you start the proxy yourself. It forwards your Claude Code traffic after compressing it, and is off unless you turn it on.
124
+
125
+ Outside the Agent Runner and the TokenStack proxy — both of which you start deliberately, and both of which talk to Anthropic rather than to us — **no code, file contents, file paths, usernames, project names, or prompts are ever sent.** The environment fields in license validation exist only so platform-specific breakage (for example, a bug that affects only Linux) is visible to us in aggregate.
108
126
 
109
127
  ### Environment Variable Override
110
128
 
@@ -116,7 +134,7 @@ export MEMSTACK_SKILLS_DIR=/path/to/your/memstack/skills
116
134
 
117
135
  ## Stack
118
136
 
119
- - Python 3.12+
137
+ - Python 3.10+
120
138
  - [MCP SDK](https://pypi.org/project/mcp/) (stdio transport)
121
139
  - [LanceDB](https://lancedb.com/) (vector storage, zero external dependencies)
122
140
  - [sentence-transformers](https://www.sbert.net/) with `all-MiniLM-L6-v2` (384-dim local embeddings)
@@ -170,7 +188,7 @@ The `config.json` file controls where skills are loaded from:
170
188
  "skill_sources": [
171
189
  {
172
190
  "type": "local",
173
- "path": "C:\\Projects\\memstack\\skills",
191
+ "path": "/path/to/memstack/skills",
174
192
  "pattern": "**/SKILL.md",
175
193
  "label": "MemStack"
176
194
  }
@@ -182,7 +200,9 @@ The `config.json` file controls where skills are loaded from:
182
200
  }
183
201
  ```
184
202
 
185
- Pro skills are **auto-detected** when `MEMSTACK_PRO_LICENSE_KEY` is set, no need to add them to `config.json`.
203
+ `vector_db_path` sets where the skill index is stored. A relative value resolves against the canonical state root `~/.memstack`, not against the directory holding `config.json`, so the index lives in one place regardless of which directory a process is started from. An absolute or `~`-prefixed value is honored verbatim.
204
+
205
+ You never add Pro skills to `config.json` by hand: the loader adds that directory itself once a key is present. Run `activate_license` at least once regardless, because that is the step that validates your key and downloads the Pro skills. `MEMSTACK_PRO_LICENSE_KEY` is an optional override that supplies the key without storing it, and it takes precedence over the stored one, but on its own it downloads nothing.
186
206
 
187
207
  Add entries to `skill_sources` to index skills from multiple directories:
188
208
 
@@ -191,7 +211,7 @@ Add entries to `skill_sources` to index skills from multiple directories:
191
211
  "skill_sources": [
192
212
  {
193
213
  "type": "local",
194
- "path": "C:\\Projects\\memstack\\skills",
214
+ "path": "/path/to/memstack/skills",
195
215
  "pattern": "**/SKILL.md",
196
216
  "label": "MemStack"
197
217
  },
@@ -211,20 +231,28 @@ The `pattern` field controls how skills are discovered:
211
231
 
212
232
  ## Release Notes
213
233
 
214
- ### v4.0.0 (May 2026)
234
+ ### 4.15.0 (August 2026)
235
+
236
+ - The skill index moved to the canonical state root, so a relative `vector_db_path` no longer depends on which directory the server happened to start in. **The first start after installing or upgrading rebuilds the index once, which takes roughly a minute**, nearly all of it loading the embedding model. Later starts are unaffected.
237
+ - New index guard classifies the index as current, drift, stale, absent, or rebuilding, and reports that verdict at startup and in the dashboard. Only startup may rebuild on its own, so no search request ever blocks on one.
238
+ - Agent Runner git policy rewritten as an argv-level classifier, replacing a substring match that could not tell `git status` from `git push`.
239
+
240
+ ### 4.10.0 to 4.14.1 (July 2026)
241
+
242
+ - Memory Engine: diary `## FACTS` ingestion, living-memory injection at session start, a read-only Memory Inspector dashboard page, and recall that ranks the whole live fact set rather than a window of it.
243
+ - Added the goal skill, bringing the public catalog to 130 skills (86 free + 44 Pro).
244
+ - Added the video-review Pro skill.
245
+ - Referrals page added to the dashboard.
246
+ - License validation now discloses its full payload in-product (see [Data and privacy](#data-and-privacy)).
247
+ - Packaging fix: `skill_descriptions.json` now ships in the wheel, so a pip install no longer falls back to empty dashboard descriptions.
215
248
 
216
- - Dashboard: 6-page localhost dashboard (Overview, Skills Manager, Burn Report, Memory Browser, Agent Monitor, Settings)
217
- - Agent Runner: 3-agent orchestration (Manager/Builder/Reviewer) with per-agent model selection
218
- - 17 MCP tools
219
- - 127 skills (84 free + 43 Pro)
220
- - Real-time context window monitoring per agent
221
- - Session diary with AI-authored markdown narratives
222
- - Safe git staging (prevents accidental commits of secrets/runtime data)
223
- - Task completion notifications (browser, tab flash, audio)
224
- - Token usage tracking with estimated costs
225
- - TokenStack™ proxy integration (~35-40% token savings)
249
+ ### 4.0.0 to 4.9.0 (May to July 2026)
226
250
 
227
- **[v3.4.0](https://github.com/cwinvestments/memstack-skill-loader/releases/tag/v3.4.0)**: 100 Skills Milestone (18 new Pro skills, auto-detection, display name fixes)
251
+ - Dashboard and Agent Runner: 3-agent orchestration (Manager, Builder, Reviewer) with per-agent model selection, context window monitoring, and token cost tracking.
252
+ - Session diary with markdown narratives, and safe git staging that keeps secrets and runtime data out of commits.
253
+ - TokenStack proxy compression, including AST compression of line-numbered Python.
254
+ - Memory Browser with project filtering and secret masking.
255
+ - Licensing hardened against transient network failures and machine mismatches.
228
256
 
229
257
  ## License
230
258
 
@@ -0,0 +1,51 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "memstack-skill-loader"
7
+ version = "4.15.0"
8
+ description = "MCP server that vector-indexes MemStack Pro skills for on-demand loading"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ # Upper bound is load-bearing: mcp 2.0.0 (2026-07-28) removed the
13
+ # Server.list_tools()/call_tool() decorator API that server.py is built on.
14
+ # Do not relax without porting server.py to the 2.x API first.
15
+ "mcp>=1.0.0,<2.0.0",
16
+ "lancedb>=0.6.0",
17
+ "sentence-transformers>=2.2.0",
18
+ "pyarrow>=14.0.0",
19
+ "httpx>=0.24.0",
20
+ "aiohttp>=3.9",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://memstack.pro"
25
+ Documentation = "https://memstack.pro/docs"
26
+
27
+ [project.optional-dependencies]
28
+ # setuptools is a TEST dependency here, not only a build dependency. The
29
+ # packaging guard in tests/test_wheel_contents.py builds a wheel and inspects
30
+ # it, and it fails rather than skips when the backend is absent, because a skip
31
+ # is a silent pass. Python 3.12+ venvs no longer ship setuptools, so a bare venv
32
+ # needs: pip install -e ".[dev]"
33
+ dev = ["setuptools>=68"]
34
+
35
+ [project.scripts]
36
+ memstack-index = "memstack_skill_loader.indexer:main"
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+
41
+ [tool.setuptools.package-data]
42
+ memstack_skill_loader = ["dashboard.html", "skill_descriptions.json"]
43
+
44
+ [tool.pytest.ini_options]
45
+ # Test the WORKING TREE, not whatever is installed. This package is installed
46
+ # non-editable, so without this the suite imported memstack_skill_loader from
47
+ # site-packages and silently graded a stale copy: a source change could be
48
+ # green here and still be broken, and a new test could fail against code that
49
+ # was already fixed. pythonpath puts src/ ahead of site-packages for the whole
50
+ # suite, so `python -m pytest` needs no PYTHONPATH prefix to be correct.
51
+ pythonpath = ["src"]
@@ -1,3 +1,3 @@
1
1
  """MemStack Skill Loader — MCP server for semantic skill search."""
2
2
 
3
- __version__ = "4.14.0"
3
+ __version__ = "4.15.0"
@@ -24,6 +24,9 @@ from .stats import log_agent_invocation, log_api_cost
24
24
  # ---------------------------------------------------------------------------
25
25
 
26
26
  MODEL_PRICING = {
27
+ "claude-fable-5": {"input": 10.0, "output": 50.0},
28
+ "claude-opus-5": {"input": 5.0, "output": 25.0},
29
+ "claude-sonnet-5": {"input": 3.0, "output": 15.0},
27
30
  "claude-sonnet-4-6": {"input": 3.0, "output": 15.0},
28
31
  "claude-opus-4-6": {"input": 5.0, "output": 25.0},
29
32
  "claude-opus-4-7": {"input": 5.0, "output": 25.0},
@@ -177,7 +180,15 @@ SYSTEM_PROMPTS = {
177
180
  "- Never hardcode secrets, API keys, tokens, passwords, or credentials in source code. "
178
181
  "Always use environment variables loaded from .env files. If a secret is needed, create "
179
182
  "or update a .env.example file with the variable name and a placeholder value.\n"
180
- "- Do NOT run git add, git commit, or any git commands. Only make file changes."
183
+ "- Read-only git IS available to you: status, log, diff, show, ls-files, "
184
+ "check-ignore, branch/remote listing, ls-remote, rev-parse. Use it to "
185
+ "understand the repository before you change it.\n"
186
+ "- Do NOT run git add, git commit, git push, git merge, git checkout, or "
187
+ "git reset. Committing is the orchestrator's job, not yours. These are "
188
+ "denied in code, not on the honour system, so do not try to work around "
189
+ "the denial.\n"
190
+ "- Issue ONE git command per Bash call. Chaining with && or ; is denied, "
191
+ "as are output redirection and `git -C <other-repo>`."
181
192
  ),
182
193
  "advisor": (
183
194
  "You are an Advisor agent. You are called in ONLY when a Builder agent has failed "
@@ -214,6 +225,11 @@ SYSTEM_PROMPTS = {
214
225
  "verdict that the orchestrator parses as a hard contract.\n\n"
215
226
  "You MUST read the actual changed files to verify correctness. Do not trust the Builder's "
216
227
  "summary alone.\n\n"
228
+ "Read-only git is available to you for verification: status, log, diff, show, ls-files, "
229
+ "branch/remote listing, ls-remote, rev-parse, symbolic-ref. Git writes (commit, push, "
230
+ "merge, checkout, reset, fetch) are denied in code. Issue ONE git command per Bash call: "
231
+ "chaining with && or ;, output redirection, and `git -C <other-repo>` are all denied, so "
232
+ "run them as separate calls rather than trying to combine them.\n\n"
217
233
  "## Review Process\n\n"
218
234
  "Evaluate the submission across these 4 perspectives:\n"
219
235
  "1. **SECURITY** — secret/credential exposure, injection risks, auth/permission changes, "
@@ -1062,6 +1078,19 @@ def _build_env(strip_api_key: bool = False, inject_api_key: str | None = None) -
1062
1078
  env["ANTHROPIC_API_KEY"] = inject_api_key
1063
1079
  if ANTHROPIC_BASE_URL:
1064
1080
  env["ANTHROPIC_BASE_URL"] = ANTHROPIC_BASE_URL
1081
+ # Git hardening for agent subprocesses. A PreToolUse hook can only allow or
1082
+ # deny, never rewrite, so the vectors that live in repo-local config are
1083
+ # closed here instead (AGENT_GIT_CAPABILITY_DESIGN.md §1.2):
1084
+ # GIT_PAGER - .git/config core.pager is arbitrary code execution
1085
+ # GIT_EXTERNAL_DIFF - .gitattributes can point `git diff` at a program
1086
+ # GIT_CONFIG_NOSYSTEM- ignore system-wide config the agent could reach
1087
+ # GIT_TERMINAL_PROMPT- a network read against an unauthenticated remote
1088
+ # must error, not hang until the inactivity watchdog
1089
+ env["GIT_PAGER"] = "cat"
1090
+ env["GIT_EXTERNAL_DIFF"] = ""
1091
+ env["GIT_CONFIG_NOSYSTEM"] = "1"
1092
+ env["GIT_TERMINAL_PROMPT"] = "0"
1093
+ env["GIT_ASKPASS"] = ""
1065
1094
  return env
1066
1095
 
1067
1096
 
@@ -1764,13 +1793,33 @@ def _parse_subtasks(text: str) -> list[tuple[str, str, list[str]]]:
1764
1793
 
1765
1794
 
1766
1795
  def _build_builder_hook_settings() -> str:
1767
- """Inline --settings JSON that registers the Builder git-deny PreToolUse hook.
1796
+ """Inline --settings JSON that registers the Builder git PreToolUse hook.
1768
1797
 
1769
1798
  The hook script ships inside this package (hooks/deny_git.py). Its absolute
1770
1799
  path MUST use forward slashes: backslashes get stripped when the settings
1771
1800
  command string is executed on Windows, which mangles the path and breaks
1772
- the hook (see smoke test)."""
1801
+ the hook (see smoke test).
1802
+
1803
+ The matcher covers the file-writing tools as well as Bash because the hook
1804
+ now also protects .gitattributes / .gitconfig / .git/** from being authored
1805
+ (AGENT_GIT_CAPABILITY_DESIGN.md §1.3); a Bash-only matcher would leave the
1806
+ Write/Edit route wide open."""
1773
1807
  hook_script = os.path.join(os.path.dirname(__file__), "hooks", "deny_git.py").replace("\\", "/")
1808
+ return json.dumps({
1809
+ "hooks": {"PreToolUse": [{"matcher": "Write|Edit|MultiEdit|NotebookEdit|Bash",
1810
+ "hooks": [{"type": "command", "command": f"python {hook_script}"}]}]}
1811
+ })
1812
+
1813
+
1814
+ def _build_reviewer_hook_settings() -> str:
1815
+ """Inline --settings JSON that registers the Reviewer read-only-git hook.
1816
+
1817
+ Mirrors the other two builders, including the forward-slash path (Windows
1818
+ strips backslashes out of the settings command string). The Reviewer had no
1819
+ PreToolUse hook at all before this; Bash is the only matcher because the
1820
+ Reviewer must stay free to read files, build, and test in order to verify
1821
+ a deploy independently."""
1822
+ hook_script = os.path.join(os.path.dirname(__file__), "hooks", "deny_reviewer_git.py").replace("\\", "/")
1774
1823
  return json.dumps({
1775
1824
  "hooks": {"PreToolUse": [{"matcher": "Bash",
1776
1825
  "hooks": [{"type": "command", "command": f"python {hook_script}"}]}]}
@@ -2034,6 +2083,9 @@ def _orchestrate(session: Session) -> None:
2034
2083
  # Manager-only read-only hook (Layer 1). Passed to the Manager
2035
2084
  # _invoke_agent call via extra_settings; never to Builder/Reviewer.
2036
2085
  manager_hook_settings = _build_manager_hook_settings()
2086
+ # Reviewer-only read-only-git hook (Layer 1). Passed to both Reviewer
2087
+ # _invoke_agent call sites (subtask and single-task paths).
2088
+ reviewer_hook_settings = _build_reviewer_hook_settings()
2037
2089
 
2038
2090
  try:
2039
2091
  # Load execution modes and custom display names for this run
@@ -2356,6 +2408,7 @@ def _orchestrate(session: Session) -> None:
2356
2408
  model=session.models.get("reviewer", ""),
2357
2409
  display_name=display_names["reviewer"],
2358
2410
  execution_mode=agent_modes["reviewer"],
2411
+ extra_settings=reviewer_hook_settings,
2359
2412
  )
2360
2413
  try:
2361
2414
  # Gap 2: strict verdict contract, fail-closed, re-prompt at most once.
@@ -2475,6 +2528,12 @@ def _orchestrate(session: Session) -> None:
2475
2528
  _re.compile(r'__pycache__[\\/]'),
2476
2529
  _re.compile(r'node_modules[\\/]'),
2477
2530
  _re.compile(r'^\.env'),
2531
+ # Repository config: never auto-staged. A .gitattributes
2532
+ # or .git/config change can turn read-only git into code
2533
+ # execution (AGENT_GIT_CAPABILITY_DESIGN.md §1.3).
2534
+ _re.compile(r'(^|[\\/])\.gitattributes$'),
2535
+ _re.compile(r'(^|[\\/])\.gitconfig$'),
2536
+ _re.compile(r'(^|[\\/])\.git[\\/]'),
2478
2537
  _re.compile(r'secret', _re.IGNORECASE),
2479
2538
  _re.compile(r'credential', _re.IGNORECASE),
2480
2539
  ]
@@ -2730,6 +2789,7 @@ def _orchestrate(session: Session) -> None:
2730
2789
  model=session.models.get("reviewer", ""),
2731
2790
  display_name=display_names["reviewer"],
2732
2791
  execution_mode=agent_modes["reviewer"],
2792
+ extra_settings=reviewer_hook_settings,
2733
2793
  )
2734
2794
  try:
2735
2795
  # Gap 2: strict verdict contract, fail-closed, re-prompt at most once.
@@ -2793,6 +2853,12 @@ def _orchestrate(session: Session) -> None:
2793
2853
  _re.compile(r'__pycache__[\\/]'),
2794
2854
  _re.compile(r'node_modules[\\/]'),
2795
2855
  _re.compile(r'^\.env'),
2856
+ # Repository config: never auto-staged. A .gitattributes
2857
+ # or .git/config change can turn read-only git into
2858
+ # code execution (AGENT_GIT_CAPABILITY_DESIGN.md §1.3).
2859
+ _re.compile(r'(^|[\\/])\.gitattributes$'),
2860
+ _re.compile(r'(^|[\\/])\.gitconfig$'),
2861
+ _re.compile(r'(^|[\\/])\.git[\\/]'),
2796
2862
  _re.compile(r'secret', _re.IGNORECASE),
2797
2863
  _re.compile(r'credential', _re.IGNORECASE),
2798
2864
  ]
@@ -18,7 +18,6 @@ CATEGORY_MAP = {
18
18
  "humanize": "Content", "blog-post": "Content", "email-sequence": "Content",
19
19
  "landing-page-copy": "Content", "newsletter": "Content", "product-description": "Content",
20
20
  "tiktok-script": "Content", "twitter-thread": "Content", "youtube-script": "Content",
21
- "kdp-format": "Content",
22
21
  # Deployment
23
22
  "railway-deploy": "Deployment", "docker-setup": "Deployment", "netlify-deploy": "Deployment",
24
23
  "domain-ssl": "Deployment", "hetzner-setup": "Deployment", "ci-cd-pipeline": "Deployment",