mishkan-harness 0.2.0 → 0.2.4

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 (116) hide show
  1. package/README.md +108 -172
  2. package/bin/mishkan.js +677 -16
  3. package/docs/design/MISHKAN_decisions.md +450 -8
  4. package/docs/design/MISHKAN_harness_design.md +1 -33
  5. package/docs/design/MISHKAN_observability.md +13 -9
  6. package/docs/engineer/profile-readable.md +201 -0
  7. package/docs/engineer/profile.md +754 -0
  8. package/docs/research/graphify-token-saving-poc.md +108 -0
  9. package/docs/usage/09-workflows.md +74 -4
  10. package/docs/usage/10-observability.md +37 -13
  11. package/docs/usage/11-graphify.md +264 -0
  12. package/docs/usage/12-skill-discovery.md +294 -0
  13. package/docs/usage/README.md +5 -3
  14. package/package.json +1 -1
  15. package/payload/install/settings.hooks.json +24 -0
  16. package/payload/mishkan/AGENT_SPEC.md +25 -7
  17. package/payload/mishkan/agents/ahikam.md +4 -2
  18. package/payload/mishkan/agents/aholiab.md +4 -2
  19. package/payload/mishkan/agents/asaph.md +5 -2
  20. package/payload/mishkan/agents/baruch.md +19 -2
  21. package/payload/mishkan/agents/benaiah.md +4 -2
  22. package/payload/mishkan/agents/bezalel.md +4 -2
  23. package/payload/mishkan/agents/caleb.md +4 -2
  24. package/payload/mishkan/agents/deborah.md +4 -2
  25. package/payload/mishkan/agents/elasah.md +4 -2
  26. package/payload/mishkan/agents/eliashib.md +4 -2
  27. package/payload/mishkan/agents/ezra.md +4 -2
  28. package/payload/mishkan/agents/hanun.md +5 -2
  29. package/payload/mishkan/agents/hiram.md +5 -2
  30. package/payload/mishkan/agents/hizkiah.md +5 -2
  31. package/payload/mishkan/agents/huldah.md +4 -2
  32. package/payload/mishkan/agents/huram.md +4 -2
  33. package/payload/mishkan/agents/hushai.md +5 -2
  34. package/payload/mishkan/agents/igal.md +4 -2
  35. package/payload/mishkan/agents/ira.md +5 -2
  36. package/payload/mishkan/agents/jahaziel.md +5 -2
  37. package/payload/mishkan/agents/jakin.md +4 -2
  38. package/payload/mishkan/agents/jehonathan.md +5 -2
  39. package/payload/mishkan/agents/jehoshaphat.md +4 -2
  40. package/payload/mishkan/agents/joab.md +5 -2
  41. package/payload/mishkan/agents/joah.md +5 -2
  42. package/payload/mishkan/agents/maaseiah.md +4 -2
  43. package/payload/mishkan/agents/meremoth.md +5 -2
  44. package/payload/mishkan/agents/meshullam.md +5 -2
  45. package/payload/mishkan/agents/nathan.md +5 -2
  46. package/payload/mishkan/agents/nehemiah.md +4 -2
  47. package/payload/mishkan/agents/obed.md +4 -2
  48. package/payload/mishkan/agents/oholiab.md +5 -2
  49. package/payload/mishkan/agents/palal.md +5 -2
  50. package/payload/mishkan/agents/phinehas.md +4 -2
  51. package/payload/mishkan/agents/rehum.md +4 -2
  52. package/payload/mishkan/agents/salma.md +5 -2
  53. package/payload/mishkan/agents/seraiah.md +4 -2
  54. package/payload/mishkan/agents/shallum.md +5 -2
  55. package/payload/mishkan/agents/shaphan.md +4 -2
  56. package/payload/mishkan/agents/shemaiah.md +4 -2
  57. package/payload/mishkan/agents/shevna.md +5 -2
  58. package/payload/mishkan/agents/uriah.md +5 -2
  59. package/payload/mishkan/agents/zaccur.md +4 -2
  60. package/payload/mishkan/agents/zadok.md +5 -2
  61. package/payload/mishkan/agents/zerubbabel.md +4 -2
  62. package/payload/mishkan/commands/code-graph.md +35 -0
  63. package/payload/mishkan/commands/eval-baruch.md +57 -0
  64. package/payload/mishkan/commands/mishkan-org-reference.md +58 -0
  65. package/payload/mishkan/commands/mishkan-resume.md +19 -5
  66. package/payload/mishkan/commands/mishkan-skills-misses.md +47 -0
  67. package/payload/mishkan/commands/mishkan-skills-reindex.md +33 -0
  68. package/payload/mishkan/commands/skills.md +35 -0
  69. package/payload/mishkan/commands/sprint-close.md +3 -1
  70. package/payload/mishkan/hooks/pre-tool-knowledge-route.sh +231 -0
  71. package/payload/mishkan/hooks/pre-tool-task-skill-route.sh +122 -0
  72. package/payload/mishkan/hooks/session-start-skill-index.sh +35 -0
  73. package/payload/mishkan/observability/schema.json +1 -1
  74. package/payload/mishkan/observability/watch/src/mishkan_watch/__main__.py +84 -2
  75. package/payload/mishkan/observability/watch/src/mishkan_watch/app.py +64 -3
  76. package/payload/mishkan/observability/watch/src/mishkan_watch/org_data.py +79 -0
  77. package/payload/mishkan/observability/watch/src/mishkan_watch/skills_data.py +267 -0
  78. package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/agents.py +33 -1
  79. package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/knowledge.py +118 -9
  80. package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/live.py +102 -2
  81. package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/org.py +139 -0
  82. package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/skills.py +187 -0
  83. package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/usage.py +377 -0
  84. package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/workflows.py +199 -27
  85. package/payload/mishkan/observability/watch/src/mishkan_watch/theme.tcss +78 -4
  86. package/payload/mishkan/observability/watchd/src/mishkan_watchd/__main__.py +36 -6
  87. package/payload/mishkan/observability/watchd/src/mishkan_watchd/sources/bus_tail.py +16 -3
  88. package/payload/mishkan/observability/watchd/src/mishkan_watchd/sources/graphify_tail.py +220 -0
  89. package/payload/mishkan/observability/watchd/src/mishkan_watchd/sources/worktree_poll.py +13 -2
  90. package/payload/mishkan/observability/watchd/src/mishkan_watchd/state.py +157 -3
  91. package/payload/mishkan/observability/watchd/tests/test_state.py +6 -2
  92. package/payload/mishkan/org/org.json +141 -0
  93. package/payload/mishkan/scripts/pre-commit-eval-gate.sh +50 -0
  94. package/payload/mishkan/scripts/skill-discovery-indexer.py +462 -0
  95. package/payload/mishkan/scripts/skill-discovery-misses.py +173 -0
  96. package/payload/mishkan/scripts/skill-discovery-router.py +457 -0
  97. package/payload/mishkan/scripts/skill-discovery-smoke.sh +156 -0
  98. package/payload/mishkan/skills/graphify-query-craft/SKILL.md +162 -0
  99. package/payload/mishkan/skills/mishkan-init/SKILL.md +15 -0
  100. package/payload/mishkan/skills/skill-discovery/SKILL.md +120 -0
  101. package/payload/mishkan/templates/case-node.schema.json +1 -0
  102. package/payload/mishkan/templates/observability-log.schema.json +1 -0
  103. package/payload/mishkan/workflows/README.md +78 -13
  104. package/payload/mishkan/workflows/chosheb-feature-ship.js +75 -0
  105. package/payload/mishkan/workflows/migdal-dr-drill.js +94 -0
  106. package/payload/mishkan/workflows/migdal-infra-change.js +67 -0
  107. package/payload/mishkan/workflows/mishkan-blast-radius.js +144 -0
  108. package/payload/mishkan/workflows/mishkan-init.js +58 -0
  109. package/payload/mishkan/workflows/mishkan-knowledge-gap-discovery.js +121 -0
  110. package/payload/mishkan/workflows/mishkan-standards-rollout.js +153 -0
  111. package/payload/mishkan/workflows/mishmar-security-gate.js +83 -0
  112. package/payload/mishkan/workflows/panim-ds-rollout.js +83 -0
  113. package/payload/mishkan/workflows/sefer-release-notes.js +85 -0
  114. package/payload/mishkan/workflows/yasad-data-migration-wave.js +78 -0
  115. package/payload/mishkan/workflows/yasad-schema-evolution.js +76 -0
  116. package/payload/mishkan/templates/user-CLAUDE.md +0 -62
@@ -0,0 +1,294 @@
1
+ # 12 — Skill discovery
2
+
3
+ > Goal: surface the right installed skills for the current task without
4
+ > bloating context. Universal indexer + 3-mechanism router + 3-bucket
5
+ > output. Advisory — the model decides what to load. Decision: see
6
+ > [D-011](../design/MISHKAN_decisions.md#d-011--universal-skill-discovery-layer-added-2026-06-07).
7
+
8
+ ## Why this exists
9
+
10
+ The harness ships 40+ MISHKAN craft skills, and the user surface adds
11
+ dozens more (`~/.claude/skills/`, plugin-bundled, project-local). Two
12
+ failure modes compete: silent reinvention (work that a skill already
13
+ encodes), and context bloat (loading too many skills "just in case"). The
14
+ discovery layer collapses that tension into a single advisory pass.
15
+
16
+ ## What gets installed
17
+
18
+ | Component | Path | Role |
19
+ |---|---|---|
20
+ | Indexer | `~/.claude/mishkan/scripts/skill-discovery-indexer.py` | Scans every skill root, writes `index.json` |
21
+ | Router | `~/.claude/mishkan/scripts/skill-discovery-router.py` | Reads index, scores skills for a task, emits 3 buckets |
22
+ | Skill | `~/.claude/mishkan/skills/skill-discovery/` | Tells the main session how to invoke + interpret |
23
+ | `/skills` | `~/.claude/commands/skills.md` | Run the router on the current task |
24
+ | `/mishkan-skills-reindex` | `~/.claude/commands/mishkan-skills-reindex.md` | Manual full rebuild |
25
+
26
+ Output lands at `~/.claude/mishkan/skill-discovery/`:
27
+
28
+ ```
29
+ index.json — universal index, one entry per indexed skill
30
+ misses.jsonl — every empty-result routing (tuning signal)
31
+ indexer-errors.jsonl — per-skill indexer failures
32
+ ```
33
+
34
+ ## Roots scanned (precedence order)
35
+
36
+ The indexer scans these roots **in order**. First hit on a name wins;
37
+ shadowed entries are recorded in `meta.collisions`, not silently dropped:
38
+
39
+ 1. `~/.claude/mishkan/skills/` — `origin = mishkan`
40
+ 2. `~/.claude/skills/` — `origin = user`
41
+ 3. `~/.claude/plugins/*/skills/` — `origin = plugin`
42
+ 4. `<repo>/.claude/skills/` — `origin = project`
43
+
44
+ ## Indexer commands
45
+
46
+ ```bash
47
+ # Full rescan (install/update default)
48
+ python3 ~/.claude/mishkan/scripts/skill-discovery-indexer.py --rebuild
49
+
50
+ # Cheap session-boot sweep (rebuilds only if mtime is newer than last_scan)
51
+ python3 ~/.claude/mishkan/scripts/skill-discovery-indexer.py --stat-only
52
+
53
+ # Manual rebuild (records manual=True in meta)
54
+ python3 ~/.claude/mishkan/scripts/skill-discovery-indexer.py --manual
55
+ ```
56
+
57
+ ## Router usage
58
+
59
+ The router accepts a task description on `--task` or on stdin, and emits a
60
+ 3-bucket JSON to stdout:
61
+
62
+ ```bash
63
+ python3 ~/.claude/mishkan/scripts/skill-discovery-router.py \
64
+ --task "Refactor the auth module to use JWT with refresh tokens" \
65
+ --relevant-categories security,backend
66
+ ```
67
+
68
+ Output shape (abbreviated):
69
+
70
+ ```json
71
+ {
72
+ "task_summary": "...",
73
+ "must_load": [
74
+ { "name": "auth-implementation-patterns", "score": 7.2, "origin": "user",
75
+ "category": "security", "trust": "third-party (user); ..." }
76
+ ],
77
+ "should_consider": [ ... ],
78
+ "adjacent": [ ... ],
79
+ "total_returned": 6,
80
+ "warnings": [],
81
+ "stale_rebuild_needed": false
82
+ }
83
+ ```
84
+
85
+ ## The 3 buckets — semantics
86
+
87
+ | Bucket | Cap | When it fires | What the model does |
88
+ |---|---|---|---|
89
+ | `must_load` | ≤ 3 | Score ≥ `threshold_high` (default 4.0) and strong trigger match | Load these into context as the directly-relevant skills. |
90
+ | `should_consider` | ≤ 5 | Mid-band (≥ `threshold_mid`, < `threshold_high`) | Skim description; load if the work clearly intersects. |
91
+ | `adjacent` | ≤ 5 | Low score, same category | Awareness only; mention if helpful; do not load. |
92
+
93
+ **Hard cap:** 13 total. **Bias rule:** prefer enriching `should_consider`
94
+ over padding `must_load` when scores are close — the cost of loading a
95
+ wrong skill is higher than the cost of skipping a marginal one.
96
+
97
+ ## Trust asymmetry
98
+
99
+ Every entry carries an `origin` field. Non-`mishkan` entries (origin =
100
+ `user`, `plugin`, or `project`) carry a `trust` warning in the router
101
+ output and **must not be auto-loaded for stateful operations** — the
102
+ y4nn-standards §5 boundary (git push, SSH to prod, docker exec on prod,
103
+ sudo, schema migration, log forensics). For generative work, third-party
104
+ skills are fine to load once you've read the description.
105
+
106
+ ## Refresh triggers
107
+
108
+ | Trigger | Mode | Notes |
109
+ |---|---|---|
110
+ | Install / update | `--rebuild` | Full rescan; runs once at install time |
111
+ | Session boot | `--stat-only` | mtime sweep vs `meta.last_scan`; rebuilds only on change |
112
+ | Manual | `--manual` (or `/mishkan-skills-reindex`) | Sets `meta.manual = true` |
113
+ | Stale entry at routing time | router drops + warns | `stale_rebuild_needed: true` in output |
114
+
115
+ ## Failure modes — fail-open
116
+
117
+ Everywhere:
118
+
119
+ - Indexer error on a single skill → that skill is skipped, error recorded
120
+ to `indexer-errors.jsonl`, index still writes.
121
+ - Router error → empty buckets, miss recorded to `misses.jsonl`, exit 0.
122
+ - Index missing/unreadable → router returns `stale_rebuild_needed: true`.
123
+
124
+ The discovery layer never blocks a session. If it fails, the only impact
125
+ is that you don't get the advisory pass — you fall back to memory and
126
+ explicit naming, which is exactly how the harness worked before D-011.
127
+
128
+ ## Phase 1 scope
129
+
130
+ Wired in two places only:
131
+
132
+ 1. `/skills` slash command — invoke the router on demand.
133
+ 2. `mishkan-init` workflow — `SkillRouter` phase runs early; result is
134
+ folded into Bezalel's signoff context as advisory.
135
+
136
+ Other workflows route through their existing craft skills unchanged.
137
+
138
+ ## Phase 2 — automatic discovery
139
+
140
+ Phase 2 turns "the router exists" into "agents auto-discover skills
141
+ without being asked." Three injection mechanisms ship; the `mishkan-init`
142
+ canary above stays in place — Phase 2 adds auto-routing as the dominant
143
+ path everywhere else. All three are fail-open and never block.
144
+
145
+ ### Mechanism 1 — install-time rebuild
146
+
147
+ The npm installer runs the indexer in `--rebuild` mode at the end of
148
+ phase 1, so `~/.claude/mishkan/skill-discovery/index.json` is seeded
149
+ before any session boots. A missing `python3` or an indexer error logs a
150
+ warning and the install continues; recover with
151
+ `/mishkan-skills-reindex`.
152
+
153
+ ### Mechanism 2 — SessionStart drift check
154
+
155
+ `hooks/session-start-skill-index.sh` runs on every session boot and
156
+ calls the indexer in `--stat-only` mode. It compares each indexed
157
+ SKILL.md mtime against `meta.last_scan` and rebuilds only on drift.
158
+
159
+ | Property | Value |
160
+ |---|---|
161
+ | Hook event | `SessionStart` (matcher `""`) |
162
+ | p95 budget | 200 ms |
163
+ | Worst case | full rebuild — bounded by skill file count |
164
+ | Failure mode | exit 0 silently; router surfaces `index_missing_or_unreadable` on next call |
165
+
166
+ ### Mechanism 3 — PreToolUse auto-injection on `Task` / `Agent`
167
+
168
+ `hooks/pre-tool-task-skill-route.sh` is the load-bearing piece. It:
169
+
170
+ 1. Fires only on `Task` and `Agent` tool calls (matcher `Task|Agent`,
171
+ sharing the same matcher block as `model-route.py`).
172
+ 2. Reads the Claude Code hook stdin payload, extracts
173
+ `tool_input.prompt`, and trims to 4 KB.
174
+ 3. Runs the router with `--format injection --max-injection-tokens 600`.
175
+ 4. Returns the resulting compact markdown block via the documented
176
+ PreToolUse field `hookSpecificOutput.additionalContext` — Claude
177
+ prepends it to the subagent's prompt.
178
+ 5. Skips injection entirely when the buckets are empty (no
179
+ "no skills found" noise).
180
+ 6. Emits a `hook_fire` observability event for every fire (decision =
181
+ `allow` with injection, `ok` without).
182
+
183
+ Hard caps:
184
+
185
+ - ≤ 3 `must_load` + ≤ 3 `should_consider` entries (Phase 1's `adjacent`
186
+ bucket is dropped at injection time).
187
+ - ≤ 600 tokens of prepended markdown (router enforces by trimming
188
+ `should_consider` tail-first).
189
+ - Trust marker preserved: non-`mishkan` entries are suffixed with
190
+ `(community)` in the rendered block.
191
+
192
+ | Property | Value |
193
+ |---|---|
194
+ | Hook event | `PreToolUse` (matcher `Task\|Agent`) |
195
+ | p95 budget | 100 ms |
196
+ | Hard timeout | 1.5 s (kills a wedged interpreter; still exits 0) |
197
+ | Failure mode | no output, exit 0; Task call proceeds without advisory |
198
+
199
+ ### Injection block shape
200
+
201
+ ```
202
+ ## Discovered skills (advisory)
203
+
204
+ **Load now (high relevance):**
205
+ - <name>: <one-line description>
206
+ - <name>: <one-line description>
207
+
208
+ **Consider:**
209
+ - <name>: <one-line description>
210
+
211
+ These skills were surfaced by the harness's skill-discovery router. Loading is your call.
212
+ ```
213
+
214
+ ### Disabling a mechanism per-session
215
+
216
+ Each mechanism is wired into `~/.claude/settings.json` after install. To
217
+ silence one without uninstalling the harness, edit
218
+ `settings.json` and remove the matching `hooks` entry:
219
+
220
+ | Mechanism | Match in settings.json |
221
+ |---|---|
222
+ | Install-time rebuild | (one-shot at install; nothing to disable runtime) |
223
+ | SessionStart drift check | `SessionStart` → command ending in `session-start-skill-index.sh` |
224
+ | PreToolUse Task injection | `PreToolUse` matcher `Task\|Agent` → command ending in `pre-tool-task-skill-route.sh` |
225
+
226
+ Project-local override: drop a `.claude/settings.local.json` in the
227
+ project with the same `hooks` event but an empty `hooks` array; Claude
228
+ Code merges project settings over user-level ones.
229
+
230
+ ### Misses telemetry — surfacing the signal
231
+
232
+ Every empty-bucket routing lands in `misses.jsonl`. Aggregate it with:
233
+
234
+ ```bash
235
+ python3 ~/.claude/mishkan/scripts/skill-discovery-misses.py --top 10
236
+ ```
237
+
238
+ or the slash command `/mishkan-skills-misses`. The report clusters
239
+ recurring task patterns by sorted-keyword signature, breaks down by
240
+ reason (`no_match_above_threshold`, `index_missing_or_unreadable`,
241
+ `router_exception:*`, …), and dates the observation window.
242
+
243
+ Use it at sprint close to drive the **threshold-tuning process**:
244
+
245
+ 1. Recurring pattern with count ≥ 5 and a clearly-applicable skill? Edit
246
+ the skill's `description` to include the pattern's keywords.
247
+ Description tuning is free; do it before threshold tuning.
248
+ 2. If patterns still miss after description tuning *and* scores cluster
249
+ just under `must_load`, lower `--threshold-high` from 4.0 to 3.5
250
+ (one 0.5 step, one sprint at a time).
251
+ 3. If `must_load` over-fires on marginal skills, raise `--threshold-high`
252
+ to 4.5.
253
+ 4. `router_exception:*` reasons are bugs — escalate to Bezalel, never
254
+ tune around them.
255
+
256
+ ## Troubleshooting
257
+
258
+ **`index_missing_or_unreadable` warning.**
259
+ Run `/mishkan-skills-reindex`. If that fails, inspect
260
+ `~/.claude/mishkan/skill-discovery/indexer-errors.jsonl`.
261
+
262
+ **Buckets all empty for a query that obviously matches a skill.**
263
+ The miss is already logged. Two likely causes:
264
+ - The skill's `description` does not contain the keywords the task used.
265
+ Tune the description; do not lower the threshold.
266
+ - The skill's frontmatter is malformed and the indexer skipped it. Check
267
+ `indexer-errors.jsonl`.
268
+
269
+ **A skill I expect to win the bucket is being shadowed by a duplicate
270
+ name in another root.**
271
+ Inspect `index.json.meta.collisions`. Precedence is
272
+ mishkan → user → plugin → project. Rename one of the duplicates.
273
+
274
+ **Indexer keeps rebuilding on every session boot.**
275
+ Something is touching a `SKILL.md` mtime. Check the
276
+ `meta.last_scan` value in `index.json` and compare to file mtimes under
277
+ the four roots; the offender is whatever has the newest mtime that
278
+ shouldn't.
279
+
280
+ ## Tuning the thresholds
281
+
282
+ Defaults: `threshold_high = 4.0`, `threshold_mid = 1.5`. Both are
283
+ guesses from Phase 1 scaffolding. Don't tune them until the miss log
284
+ shows a stable distribution of scores around the cutoffs across at least
285
+ 2 sprints — premature tuning chases noise.
286
+
287
+ Per-invocation overrides:
288
+
289
+ ```bash
290
+ python3 ~/.claude/mishkan/scripts/skill-discovery-router.py \
291
+ --task "..." \
292
+ --threshold-high 5.0 \
293
+ --threshold-mid 2.0
294
+ ```
@@ -46,8 +46,10 @@ You ──talk──▶ MAIN SESSION = leadership (Nehemiah/Bezalel via CLAUDE
46
46
  | 06 | [LLM provider profiles](./06-llm-providers.md) | Gemini/NVIDIA/Ollama/OpenAI/Anthropic, rate vs daily caps |
47
47
  | 07 | [Troubleshooting](./07-troubleshooting.md) | Real gotchas + fixes from the build |
48
48
  | 08 | [Glossary](./08-glossary.md) | 45-agent roster (alias → role → team), key terms |
49
- | 09 | [Dynamic Workflows](./09-workflows.md) | The 7 MISHKAN workflows, when to fire them, the cost gate |
50
- | 10 | [Observability](./10-observability.md) | Cross-session daemon + Textual TUI (opt-in); 5 tabs, status bar, troubleshooting |
49
+ | 09 | [Dynamic Workflows](./09-workflows.md) | 10 org-level + 8 team-level workflows, ADR D-010 portfolio discipline |
50
+ | 10 | [Observability](./10-observability.md) | Cross-session daemon + Textual TUI; 8 tabs (Live · Agents · Workflows · Knowledge · Activity · Org-Ref · Usage · Skills), project filter (`p`) |
51
+ | 11 | [Graphify](./11-graphify.md) | Code-structure graph; queries at ~1.8k tokens (88.1× reduction, POC-verified); D-008 + D-009 |
52
+ | 12 | [Skill discovery](./12-skill-discovery.md) | Universal indexer + 3-bucket router across MISHKAN, user, plugin, and project skills; D-011 |
51
53
 
52
54
  ## Where to start
53
55
 
@@ -60,7 +62,7 @@ You ──talk──▶ MAIN SESSION = leadership (Nehemiah/Bezalel via CLAUDE
60
62
  ## Authoritative references this documentation builds on
61
63
 
62
64
  - [`docs/design/MISHKAN_harness_design.md`](../design/MISHKAN_harness_design.md) — the 5-layer architecture and rationale.
63
- - [`docs/design/MISHKAN_decisions.md`](../design/MISHKAN_decisions.md) — D-001…D-007 with rationale.
65
+ - [`docs/design/MISHKAN_decisions.md`](../design/MISHKAN_decisions.md) — D-001…D-011 with rationale.
64
66
  - [`docs/design/MISHKAN_agent_aliases.md`](../design/MISHKAN_agent_aliases.md) — the biblical roster.
65
67
  - [`docs/design/MISHKAN_ontology.md`](../design/MISHKAN_ontology.md) — cognee entity + relationship types.
66
68
  - [`docs/design/MISHKAN_token_optimisation.md`](../design/MISHKAN_token_optimisation.md) — context economy.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mishkan-harness",
3
- "version": "0.2.0",
3
+ "version": "0.2.4",
4
4
  "description": "MISHKAN — a personal advanced SWE R&D harness for Claude Code: 45 biblically-named agents across six teams, deterministic rules + hooks, a shared research pipeline, dependency/supply-chain vetting, and a Cognee-backed knowledge graph. Installs into ~/.claude.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,6 +17,10 @@
17
17
  {
18
18
  "type": "command",
19
19
  "command": "python3 {{MISHKAN}}/hooks/model-route.py"
20
+ },
21
+ {
22
+ "type": "command",
23
+ "command": "bash {{MISHKAN}}/hooks/pre-tool-task-skill-route.sh"
20
24
  }
21
25
  ]
22
26
  },
@@ -28,6 +32,15 @@
28
32
  "command": "bash {{MISHKAN}}/hooks/pre-tool-trace.sh"
29
33
  }
30
34
  ]
35
+ },
36
+ {
37
+ "matcher": "Read|Grep",
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "command": "bash {{MISHKAN}}/hooks/pre-tool-knowledge-route.sh"
42
+ }
43
+ ]
31
44
  }
32
45
  ],
33
46
  "PostToolUse": [
@@ -41,6 +54,17 @@
41
54
  ]
42
55
  }
43
56
  ],
57
+ "SessionStart": [
58
+ {
59
+ "matcher": "",
60
+ "hooks": [
61
+ {
62
+ "type": "command",
63
+ "command": "bash {{MISHKAN}}/hooks/session-start-skill-index.sh"
64
+ }
65
+ ]
66
+ }
67
+ ],
44
68
  "Stop": [
45
69
  {
46
70
  "matcher": "",
@@ -62,8 +62,10 @@ Optional and NOT used by MISHKAN by default: `skills`, `disallowedTools`,
62
62
 
63
63
  ## Dynamic Context Injection Point
64
64
 
65
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
66
- Everything above this line is the cacheable static role prefix. -->
65
+ <!-- Cacheable prefix boundary. Everything above this line must stay
66
+ byte-identical between calls for prompt caching to fire. Project
67
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
68
+ parent session context, not injected here. -->
67
69
  ```
68
70
 
69
71
  ## 3. The Prompt Defense Baseline (verbatim, every agent)
@@ -110,13 +112,29 @@ Every agent file ends with:
110
112
 
111
113
  ## Dynamic Context Injection Point
112
114
 
113
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
114
- Everything above this line is the cacheable static role prefix. -->
115
+ <!-- Cacheable prefix boundary. Everything above this line must stay
116
+ byte-identical between calls for prompt caching to fire. Project
117
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
118
+ parent session context, not injected here. -->
115
119
  ```
116
120
 
117
- This is the marker MISHKAN's runtime uses to append project sprint state
118
- (when one exists) below the cacheable static prefix. Always present, even
119
- on roles that do not currently consume the injection.
121
+ This is a **boundary marker, not a runtime hook**. Nothing in MISHKAN
122
+ parses it at load time or splices content at the position. Its job is
123
+ twofold:
124
+
125
+ - **Author discipline.** Everything above the marker must stay byte-
126
+ identical between calls so Anthropic's prompt cache fires on the
127
+ static prefix. Putting a date, a counter, or any volatile value above
128
+ the marker breaks cacheability for that whole prefix on the next call.
129
+ - **Reader orientation.** A human reading the file sees exactly where
130
+ the cacheable role ends and where project-variable context starts.
131
+
132
+ Project sprint state from `./CLAUDE.md` does land in the agent's effective
133
+ context — but via Claude Code's normal session loading (parent session
134
+ context propagates to spawned subagents), not by injection at this
135
+ marker. The section title is kept for backwards compatibility and
136
+ because it correctly names the boundary; the comment inside has been
137
+ updated to match reality.
120
138
 
121
139
  ## 6. Body length policy
122
140
 
@@ -54,5 +54,7 @@ No `/plan` (collect-only role).
54
54
 
55
55
  ## Dynamic Context Injection Point
56
56
 
57
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
58
- Everything above this line is the cacheable static role prefix. -->
57
+ <!-- Cacheable prefix boundary. Everything above this line must stay
58
+ byte-identical between calls for prompt caching to fire. Project
59
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
60
+ parent session context, not injected here. -->
@@ -64,5 +64,7 @@ Approval gate via `/plan`.
64
64
 
65
65
  ## Dynamic Context Injection Point
66
66
 
67
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
68
- Everything above this line is the cacheable static role prefix. -->
67
+ <!-- Cacheable prefix boundary. Everything above this line must stay
68
+ byte-identical between calls for prompt caching to fire. Project
69
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
70
+ parent session context, not injected here. -->
@@ -53,6 +53,7 @@ finding:
53
53
  ## Skills (invoke on demand)
54
54
 
55
55
  - `asaph-a11y-seo-craft` — semantic-first + cite-the-SC + remediation boundary
56
+ - `graphify-query-craft` — query the project code-structure graph (~1.8k tokens vs ~80k+ grep+Read) before reading source for any structural question (who calls X, what depends on Y, where is the entry point). Per D-009 amended scope: all code-touching dev agents.
56
57
  - `accessibility-compliance` — WCAG 2.2 implementation
57
58
  - `wcag-audit-patterns` — running a WCAG audit
58
59
  - `screen-reader-testing` — AT testing
@@ -69,5 +70,7 @@ WCAG 2.2 AA minimum.
69
70
 
70
71
  ## Dynamic Context Injection Point
71
72
 
72
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
73
- Everything above this line is the cacheable static role prefix. -->
73
+ <!-- Cacheable prefix boundary. Everything above this line must stay
74
+ byte-identical between calls for prompt caching to fire. Project
75
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
76
+ parent session context, not injected here. -->
@@ -80,9 +80,26 @@ Stateful operations hard stop. Sequence before implementation. Diagnose
80
80
  before fix. Durable solutions only. No scope expansion. No fabricated
81
81
  facts. English for all output.
82
82
 
83
+ ## Contract eval
84
+
85
+ Output schema and golden-case semantic invariants exercised by
86
+ `payload/mishkan/evals/baruch/`. Not LLM-live — schema + jq assertions
87
+ on a frozen golden output. Run BEFORE any change to:
88
+
89
+ - `payload/mishkan/templates/research-log.schema.json`
90
+ - `payload/mishkan/scripts/validate-research-log.sh`
91
+ - This file
92
+ - The Baruch craft skill
93
+
94
+ Invoke via `/eval-baruch` or `bash payload/mishkan/evals/baruch/run.sh`.
95
+ CI workflow `.github/workflows/eval-baruch.yml` runs it on every PR
96
+ touching one of those paths.
97
+
83
98
  ---
84
99
 
85
100
  ## Dynamic Context Injection Point
86
101
 
87
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
88
- Everything above this line is the cacheable static role prefix. -->
102
+ <!-- Cacheable prefix boundary. Everything above this line must stay
103
+ byte-identical between calls for prompt caching to fire. Project
104
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
105
+ parent session context, not injected here. -->
@@ -72,5 +72,7 @@ Two root causes on non-trivial failures.
72
72
 
73
73
  ## Dynamic Context Injection Point
74
74
 
75
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
76
- Everything above this line is the cacheable static role prefix. -->
75
+ <!-- Cacheable prefix boundary. Everything above this line must stay
76
+ byte-identical between calls for prompt caching to fire. Project
77
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
78
+ parent session context, not injected here. -->
@@ -79,5 +79,7 @@ Approval gate on consequential decisions via `/plan`.
79
79
 
80
80
  ## Dynamic Context Injection Point
81
81
 
82
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
83
- Everything above this line is the cacheable static role prefix. -->
82
+ <!-- Cacheable prefix boundary. Everything above this line must stay
83
+ byte-identical between calls for prompt caching to fire. Project
84
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
85
+ parent session context, not injected here. -->
@@ -70,5 +70,7 @@ facts. English for all output.
70
70
 
71
71
  ## Dynamic Context Injection Point
72
72
 
73
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
74
- Everything above this line is the cacheable static role prefix. -->
73
+ <!-- Cacheable prefix boundary. Everything above this line must stay
74
+ byte-identical between calls for prompt caching to fire. Project
75
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
76
+ parent session context, not injected here. -->
@@ -59,5 +59,7 @@ No fabricated research — cite the heuristic or study.
59
59
 
60
60
  ## Dynamic Context Injection Point
61
61
 
62
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
63
- Everything above this line is the cacheable static role prefix. -->
62
+ <!-- Cacheable prefix boundary. Everything above this line must stay
63
+ byte-identical between calls for prompt caching to fire. Project
64
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
65
+ parent session context, not injected here. -->
@@ -54,5 +54,7 @@ No `/plan` (collect-only role).
54
54
 
55
55
  ## Dynamic Context Injection Point
56
56
 
57
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
58
- Everything above this line is the cacheable static role prefix. -->
57
+ <!-- Cacheable prefix boundary. Everything above this line must stay
58
+ byte-identical between calls for prompt caching to fire. Project
59
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
60
+ parent session context, not injected here. -->
@@ -64,5 +64,7 @@ No `:latest` tags. SOPS for secrets. Hardening overlay on recreate. Approval gat
64
64
 
65
65
  ## Dynamic Context Injection Point
66
66
 
67
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
68
- Everything above this line is the cacheable static role prefix. -->
67
+ <!-- Cacheable prefix boundary. Everything above this line must stay
68
+ byte-identical between calls for prompt caching to fire. Project
69
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
70
+ parent session context, not injected here. -->
@@ -65,5 +65,7 @@ facts. English for all output.
65
65
 
66
66
  ## Dynamic Context Injection Point
67
67
 
68
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
69
- Everything above this line is the cacheable static role prefix. -->
68
+ <!-- Cacheable prefix boundary. Everything above this line must stay
69
+ byte-identical between calls for prompt caching to fire. Project
70
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
71
+ parent session context, not injected here. -->
@@ -43,6 +43,7 @@ operational glue.
43
43
  ## Skills (invoke on demand)
44
44
 
45
45
  - `hanun-observability-craft` — three signals + hardening overlay always reapplied + structured logs
46
+ - `graphify-query-craft` — query the project code-structure graph (~1.8k tokens vs ~80k+ grep+Read) before reading source for any structural question (who calls X, what depends on Y, where is the entry point). Per D-009 amended scope: all code-touching dev agents.
46
47
  - `prometheus-configuration` — metrics plumbing
47
48
  - `grafana-dashboards` — dashboard work
48
49
  - `secrets-management` — secret-handling operations
@@ -60,5 +61,7 @@ Hardening overlay on every recreate. SOPS for secrets.
60
61
 
61
62
  ## Dynamic Context Injection Point
62
63
 
63
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
64
- Everything above this line is the cacheable static role prefix. -->
64
+ <!-- Cacheable prefix boundary. Everything above this line must stay
65
+ byte-identical between calls for prompt caching to fire. Project
66
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
67
+ parent session context, not injected here. -->
@@ -45,6 +45,7 @@ component contracts, or shared visual primitives).
45
45
  ## Skills (invoke on demand)
46
46
 
47
47
  - `hiram-ui-craft` — UI design + prototype handoff discipline (the depth lives here)
48
+ - `graphify-query-craft` — query the project code-structure graph (~1.8k tokens vs ~80k+ grep+Read) before reading source for any structural question (who calls X, what depends on Y, where is the entry point). Per D-009 amended scope: all code-touching dev agents.
48
49
  - `frontend-design` — production-grade UI work
49
50
  - `design-system-patterns` — tokens, theming, component patterns
50
51
  - `visual-design-foundations` — typography, hierarchy, layout
@@ -64,5 +65,7 @@ WCAG 2.2 AA on interactive components.
64
65
 
65
66
  ## Dynamic Context Injection Point
66
67
 
67
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
68
- Everything above this line is the cacheable static role prefix. -->
68
+ <!-- Cacheable prefix boundary. Everything above this line must stay
69
+ byte-identical between calls for prompt caching to fire. Project
70
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
71
+ parent session context, not injected here. -->
@@ -51,6 +51,7 @@ when a task touches more than one component.
51
51
  ## Skills (invoke on demand)
52
52
 
53
53
  - `hizkiah-implementation-craft` — any backend implementation against
54
+ - `graphify-query-craft` — query the project code-structure graph (~1.8k tokens vs ~80k+ grep+Read) before reading source for any structural question (who calls X, what depends on Y, where is the entry point). Per D-009 amended scope: all code-touching dev agents.
54
55
  a fixed contract (principles-first, with Python/FastAPI, TypeScript/Hono,
55
56
  and PHP/Laravel examples — the depth lives in this skill, not here)
56
57
  - `fastapi-templates` — FastAPI implementation (when the stack is Python)
@@ -72,5 +73,7 @@ OpenAPI contract before endpoint.
72
73
 
73
74
  ## Dynamic Context Injection Point
74
75
 
75
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
76
- Everything above this line is the cacheable static role prefix. -->
76
+ <!-- Cacheable prefix boundary. Everything above this line must stay
77
+ byte-identical between calls for prompt caching to fire. Project
78
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
79
+ parent session context, not injected here. -->
@@ -55,5 +55,7 @@ No `/plan` (collect-only role).
55
55
 
56
56
  ## Dynamic Context Injection Point
57
57
 
58
- <!-- Project sprint state from ./CLAUDE.md is injected below at runtime.
59
- Everything above this line is the cacheable static role prefix. -->
58
+ <!-- Cacheable prefix boundary. Everything above this line must stay
59
+ byte-identical between calls for prompt caching to fire. Project
60
+ sprint state from ./CLAUDE.md is loaded by Claude Code into the
61
+ parent session context, not injected here. -->