mishkan-harness 0.1.0

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 (186) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -0
  3. package/bin/mishkan.js +221 -0
  4. package/docs/design/MISHKAN_agent_aliases.md +140 -0
  5. package/docs/design/MISHKAN_decisions.md +172 -0
  6. package/docs/design/MISHKAN_harness_design.md +820 -0
  7. package/docs/design/MISHKAN_ontology.md +87 -0
  8. package/docs/design/MISHKAN_token_optimisation.md +181 -0
  9. package/docs/engineer/README.md +37 -0
  10. package/docs/engineer/profile.example.md +79 -0
  11. package/docs/usage/01-installation.md +178 -0
  12. package/docs/usage/02-project-init.md +151 -0
  13. package/docs/usage/03-orchestration.md +218 -0
  14. package/docs/usage/04-memory-layer.md +201 -0
  15. package/docs/usage/05-selective-ingest.md +177 -0
  16. package/docs/usage/06-llm-providers.md +195 -0
  17. package/docs/usage/07-troubleshooting.md +316 -0
  18. package/docs/usage/08-glossary.md +154 -0
  19. package/docs/usage/09-workflows.md +123 -0
  20. package/docs/usage/README.md +77 -0
  21. package/package.json +43 -0
  22. package/payload/install/settings.hooks.json +47 -0
  23. package/payload/mishkan/AGENT_SPEC.md +154 -0
  24. package/payload/mishkan/agents/ahikam.md +58 -0
  25. package/payload/mishkan/agents/aholiab.md +68 -0
  26. package/payload/mishkan/agents/asaph.md +73 -0
  27. package/payload/mishkan/agents/baruch.md +88 -0
  28. package/payload/mishkan/agents/benaiah.md +76 -0
  29. package/payload/mishkan/agents/bezalel.md +83 -0
  30. package/payload/mishkan/agents/caleb.md +74 -0
  31. package/payload/mishkan/agents/deborah.md +63 -0
  32. package/payload/mishkan/agents/elasah.md +58 -0
  33. package/payload/mishkan/agents/eliashib.md +68 -0
  34. package/payload/mishkan/agents/ezra.md +69 -0
  35. package/payload/mishkan/agents/hanun.md +64 -0
  36. package/payload/mishkan/agents/hiram.md +68 -0
  37. package/payload/mishkan/agents/hizkiah.md +76 -0
  38. package/payload/mishkan/agents/huldah.md +59 -0
  39. package/payload/mishkan/agents/huram.md +66 -0
  40. package/payload/mishkan/agents/hushai.md +59 -0
  41. package/payload/mishkan/agents/igal.md +58 -0
  42. package/payload/mishkan/agents/ira.md +86 -0
  43. package/payload/mishkan/agents/jahaziel.md +71 -0
  44. package/payload/mishkan/agents/jakin.md +66 -0
  45. package/payload/mishkan/agents/jehonathan.md +62 -0
  46. package/payload/mishkan/agents/jehoshaphat.md +68 -0
  47. package/payload/mishkan/agents/joab.md +71 -0
  48. package/payload/mishkan/agents/joah.md +62 -0
  49. package/payload/mishkan/agents/maaseiah.md +61 -0
  50. package/payload/mishkan/agents/meremoth.md +65 -0
  51. package/payload/mishkan/agents/meshullam.md +67 -0
  52. package/payload/mishkan/agents/nathan.md +70 -0
  53. package/payload/mishkan/agents/nehemiah.md +93 -0
  54. package/payload/mishkan/agents/obed.md +60 -0
  55. package/payload/mishkan/agents/oholiab.md +67 -0
  56. package/payload/mishkan/agents/palal.md +63 -0
  57. package/payload/mishkan/agents/phinehas.md +73 -0
  58. package/payload/mishkan/agents/rehum.md +60 -0
  59. package/payload/mishkan/agents/salma.md +69 -0
  60. package/payload/mishkan/agents/seraiah.md +73 -0
  61. package/payload/mishkan/agents/shallum.md +66 -0
  62. package/payload/mishkan/agents/shaphan.md +64 -0
  63. package/payload/mishkan/agents/shemaiah.md +67 -0
  64. package/payload/mishkan/agents/shevna.md +58 -0
  65. package/payload/mishkan/agents/uriah.md +70 -0
  66. package/payload/mishkan/agents/zaccur.md +58 -0
  67. package/payload/mishkan/agents/zadok.md +67 -0
  68. package/payload/mishkan/agents/zerubbabel.md +69 -0
  69. package/payload/mishkan/cognee/.env.curated.example +61 -0
  70. package/payload/mishkan/cognee/.env.example +165 -0
  71. package/payload/mishkan/cognee/Dockerfile +50 -0
  72. package/payload/mishkan/cognee/README.md +129 -0
  73. package/payload/mishkan/cognee/docker-compose.curated-ui.yml +61 -0
  74. package/payload/mishkan/cognee/docker-compose.curated.yml +85 -0
  75. package/payload/mishkan/cognee/docker-compose.hardening.yml +16 -0
  76. package/payload/mishkan/cognee/docker-compose.selfhosted.yml +114 -0
  77. package/payload/mishkan/cognee/docker-compose.ui.yml +70 -0
  78. package/payload/mishkan/cognee/docker-compose.yml +71 -0
  79. package/payload/mishkan/cognee/ingest-curated.py +92 -0
  80. package/payload/mishkan/commands/dep-audit.md +24 -0
  81. package/payload/mishkan/commands/mishkan-init.md +25 -0
  82. package/payload/mishkan/commands/mishkan-resume.md +21 -0
  83. package/payload/mishkan/commands/promote.md +19 -0
  84. package/payload/mishkan/commands/sefer-pull.md +19 -0
  85. package/payload/mishkan/commands/sprint-close.md +21 -0
  86. package/payload/mishkan/config/curated-library.yaml +113 -0
  87. package/payload/mishkan/config/improvement-queries.md +29 -0
  88. package/payload/mishkan/config/model-routing.yaml +87 -0
  89. package/payload/mishkan/config/projects.yaml +38 -0
  90. package/payload/mishkan/evals/baruch/README.md +93 -0
  91. package/payload/mishkan/evals/baruch/fixtures/invalid/bad-outcome-enum.json +15 -0
  92. package/payload/mishkan/evals/baruch/fixtures/invalid/bad-sprint-pattern.json +15 -0
  93. package/payload/mishkan/evals/baruch/fixtures/invalid/bad-trigger-enum.json +15 -0
  94. package/payload/mishkan/evals/baruch/fixtures/invalid/malformed-json.json +7 -0
  95. package/payload/mishkan/evals/baruch/fixtures/invalid/missing-required-field.json +14 -0
  96. package/payload/mishkan/evals/baruch/fixtures/valid/blocked-vendor.json +15 -0
  97. package/payload/mishkan/evals/baruch/fixtures/valid/curated-shortcircuit.json +15 -0
  98. package/payload/mishkan/evals/baruch/fixtures/valid/partial-no-write.json +14 -0
  99. package/payload/mishkan/evals/baruch/fixtures/valid/resolved-cross-harness.json +15 -0
  100. package/payload/mishkan/evals/baruch/golden_case/expected.yaml +35 -0
  101. package/payload/mishkan/evals/baruch/golden_case/input.yaml +47 -0
  102. package/payload/mishkan/evals/baruch/golden_case/produced.json +15 -0
  103. package/payload/mishkan/evals/baruch/run.sh +129 -0
  104. package/payload/mishkan/hooks/model-route.py +96 -0
  105. package/payload/mishkan/hooks/post-tool-observe.sh +45 -0
  106. package/payload/mishkan/hooks/pre-tool-security.sh +150 -0
  107. package/payload/mishkan/hooks/session-start.sh +20 -0
  108. package/payload/mishkan/hooks/stop-reporter.sh +29 -0
  109. package/payload/mishkan/ontology.md +87 -0
  110. package/payload/mishkan/rules/backend/yasad.md +23 -0
  111. package/payload/mishkan/rules/common/dependencies.md +53 -0
  112. package/payload/mishkan/rules/common/quality.md +16 -0
  113. package/payload/mishkan/rules/common/security.md +20 -0
  114. package/payload/mishkan/rules/documentation/sefer.md +19 -0
  115. package/payload/mishkan/rules/frontend/panim.md +21 -0
  116. package/payload/mishkan/rules/infrastructure/migdal.md +22 -0
  117. package/payload/mishkan/scripts/dependency-audit.sh +171 -0
  118. package/payload/mishkan/scripts/ensure-curated-box.sh +66 -0
  119. package/payload/mishkan/scripts/mishkan-ingest.sh +92 -0
  120. package/payload/mishkan/scripts/observability-aggregate.sh +57 -0
  121. package/payload/mishkan/scripts/seed-curated-library.sh +62 -0
  122. package/payload/mishkan/scripts/sync-profile.sh +65 -0
  123. package/payload/mishkan/scripts/validate-research-log.sh +108 -0
  124. package/payload/mishkan/skills/asaph-a11y-seo-craft/SKILL.md +289 -0
  125. package/payload/mishkan/skills/baruch-research-reporting-craft/SKILL.md +460 -0
  126. package/payload/mishkan/skills/benaiah-devsecops-craft/SKILL.md +329 -0
  127. package/payload/mishkan/skills/bezalel-cto-craft/SKILL.md +391 -0
  128. package/payload/mishkan/skills/caleb-web-research-craft/SKILL.md +306 -0
  129. package/payload/mishkan/skills/cognee-promote/SKILL.md +40 -0
  130. package/payload/mishkan/skills/cognee-quickstart/SKILL.md +66 -0
  131. package/payload/mishkan/skills/context-compress/SKILL.md +36 -0
  132. package/payload/mishkan/skills/deborah-ux-craft/SKILL.md +295 -0
  133. package/payload/mishkan/skills/dependency-audit/SKILL.md +59 -0
  134. package/payload/mishkan/skills/dependency-vetting/SKILL.md +59 -0
  135. package/payload/mishkan/skills/documentation-craft/SKILL.md +468 -0
  136. package/payload/mishkan/skills/ezra-research-formulation-craft/SKILL.md +319 -0
  137. package/payload/mishkan/skills/hanun-observability-craft/SKILL.md +312 -0
  138. package/payload/mishkan/skills/hiram-ui-craft/SKILL.md +334 -0
  139. package/payload/mishkan/skills/hizkiah-implementation-craft/SKILL.md +701 -0
  140. package/payload/mishkan/skills/hushai-security-advisor-craft/SKILL.md +282 -0
  141. package/payload/mishkan/skills/ira-code-security-craft/SKILL.md +553 -0
  142. package/payload/mishkan/skills/jakin-intent-clarification-craft/SKILL.md +299 -0
  143. package/payload/mishkan/skills/jehonathan-publication-craft/SKILL.md +262 -0
  144. package/payload/mishkan/skills/joab-app-security-craft/SKILL.md +266 -0
  145. package/payload/mishkan/skills/meremoth-devops-craft/SKILL.md +298 -0
  146. package/payload/mishkan/skills/meshullam-infra-design-craft/SKILL.md +302 -0
  147. package/payload/mishkan/skills/mishkan-ingest/SKILL.md +65 -0
  148. package/payload/mishkan/skills/mishkan-init/SKILL.md +65 -0
  149. package/payload/mishkan/skills/nathan-architecture-craft/SKILL.md +547 -0
  150. package/payload/mishkan/skills/nehemiah-pm-craft/SKILL.md +484 -0
  151. package/payload/mishkan/skills/obed-asset-pipeline-craft/SKILL.md +286 -0
  152. package/payload/mishkan/skills/oholiab-design-system-craft/SKILL.md +334 -0
  153. package/payload/mishkan/skills/palal-systems-craft/SKILL.md +281 -0
  154. package/payload/mishkan/skills/qa-evaluation-craft/SKILL.md +406 -0
  155. package/payload/mishkan/skills/rehum-sre-advisor-craft/SKILL.md +228 -0
  156. package/payload/mishkan/skills/reporter-discipline-craft/SKILL.md +351 -0
  157. package/payload/mishkan/skills/research-pipeline/SKILL.md +55 -0
  158. package/payload/mishkan/skills/salma-frontend-implementation-craft/SKILL.md +369 -0
  159. package/payload/mishkan/skills/sefer-pull/SKILL.md +37 -0
  160. package/payload/mishkan/skills/shallum-database-craft/SKILL.md +347 -0
  161. package/payload/mishkan/skills/shaphan-summarisation-craft/SKILL.md +271 -0
  162. package/payload/mishkan/skills/shemaiah-evaluation-craft/SKILL.md +342 -0
  163. package/payload/mishkan/skills/sprint-report/SKILL.md +28 -0
  164. package/payload/mishkan/skills/team-lead-craft/SKILL.md +457 -0
  165. package/payload/mishkan/skills/zadok-contract-craft/SKILL.md +520 -0
  166. package/payload/mishkan/templates/case-node.schema.json +22 -0
  167. package/payload/mishkan/templates/mcp.json +22 -0
  168. package/payload/mishkan/templates/observability-log.schema.json +24 -0
  169. package/payload/mishkan/templates/project-CLAUDE.md +47 -0
  170. package/payload/mishkan/templates/research-log.schema.json +40 -0
  171. package/payload/mishkan/templates/settings.json +12 -0
  172. package/payload/mishkan/templates/settings.local.json +6 -0
  173. package/payload/mishkan/templates/sprint-state.schema.json +47 -0
  174. package/payload/mishkan/templates/team-report.schema.json +50 -0
  175. package/payload/mishkan/templates/user-CLAUDE.md +62 -0
  176. package/payload/mishkan/workflows/README.md +88 -0
  177. package/payload/mishkan/workflows/mishkan-architecture-panel.js +156 -0
  178. package/payload/mishkan/workflows/mishkan-codebase-audit.js +188 -0
  179. package/payload/mishkan/workflows/mishkan-deep-research.js +251 -0
  180. package/payload/mishkan/workflows/mishkan-init.js +156 -0
  181. package/payload/mishkan/workflows/mishkan-migration-wave.js +180 -0
  182. package/payload/mishkan/workflows/mishkan-release-readiness.js +163 -0
  183. package/payload/mishkan/workflows/mishkan-sprint-close.js +112 -0
  184. package/payload/user/CLAUDE.md +62 -0
  185. package/payload/user/rules/engineer-standards.md +66 -0
  186. package/payload/user/rules/y4nn-standards.md +167 -0
@@ -0,0 +1,520 @@
1
+ ---
2
+ name: zadok-contract-craft
3
+ description: How Zadok reasons about backend contracts and invariants — what CONTRACT.md actually fixes, the error model, naming and pagination rules, and the discipline around contract evolution. Invoke when authoring or modifying a CONTRACT.md, debating an invariant, or deciding whether a proposed change is a backward-compatible evolution or a breaking change.
4
+ ---
5
+
6
+ # Zadok — Contract Craft
7
+
8
+ > Not a checklist. How the high priest who keeps standards across generations
9
+ > reasons when a contract is on the table — what he fixes, what he refuses to
10
+ > fix, and why he treats invariants as load-bearing.
11
+
12
+ Invoked only when a contract decision is in scope. Routine endpoint
13
+ implementation against an already-fixed contract is Hizkiah's work and does
14
+ not need this skill.
15
+
16
+ ---
17
+
18
+ ## 1. What a contract actually is
19
+
20
+ A contract is the **set of promises the system makes to its consumers that
21
+ must hold across all future versions until explicitly retired**.
22
+
23
+ Three properties distinguish a contract clause from a coding choice:
24
+
25
+ - **Observable.** Consumers can detect violation from outside the service.
26
+ - **Persistent.** It survives implementation changes. The function may be
27
+ rewritten; the contract clause stays.
28
+ - **Versioned.** Changing it requires a deliberate version step or
29
+ deprecation window — not a normal release.
30
+
31
+ If a proposed clause does not have all three, it does not belong in
32
+ `CONTRACT.md`. It is a coding convention. Document it elsewhere.
33
+
34
+ ---
35
+
36
+ ## 2. The two halves of a contract
37
+
38
+ Zadok always splits CONTRACT.md into two sections, each with different
39
+ durability:
40
+
41
+ ### 2.1 Invariants — what is always true
42
+
43
+ Statements about the system that hold for every request, every state, every
44
+ caller. Violation is a defect, never a deliberate change.
45
+
46
+ Examples:
47
+ - "Resource IDs are immutable for the life of the resource."
48
+ - "Every error response has an `error.code`, an `error.message`, and an
49
+ `error.request_id`."
50
+ - "Pagination is cursor-based; offset pagination is not offered."
51
+ - "Money fields are integer minor units (`amount_cents`), never floats."
52
+ - "Timestamps are RFC 3339 UTC strings ending in `Z`."
53
+
54
+ ### 2.2 Guarantees — what the system promises to its consumers
55
+
56
+ Statements about behaviour the system commits to deliver, often with bounds.
57
+
58
+ Examples:
59
+ - "POST /resources is idempotent over the `Idempotency-Key` header for 24h."
60
+ - "List endpoints return ≤ 100 items per page."
61
+ - "Webhooks are retried with exponential backoff for ≤ 72h, then dropped."
62
+ - "Read-after-write consistency for the same client within 5s."
63
+
64
+ The split matters. Invariants govern *shape*; guarantees govern *behaviour*.
65
+ A consumer building against guarantees can plan retry / fallback / cache
66
+ strategy. A consumer relying on invariants can plan their schema.
67
+
68
+ ---
69
+
70
+ ## 3. The questions Zadok asks before fixing any clause
71
+
72
+ 1. **Who consumes this** — internal services, external customers, both?
73
+ External consumers turn a guarantee into a *commitment* with deprecation
74
+ cost. Be cautious about what you offer them.
75
+ 2. **What changes if I tighten this** — does tightening (e.g. dropping
76
+ support for a format) break existing callers? If yes, this is a
77
+ contract-evolution decision, not a coding decision.
78
+ 3. **What changes if I loosen this** — loosening (e.g. allowing nulls
79
+ where they were forbidden) is almost always backward-compatible for
80
+ the server but rarely for the client. Pause.
81
+ 4. **Is this an invariant or a guarantee** — confusing the two is a
82
+ common source of leakage. Invariants are stricter; do not promise
83
+ them lightly.
84
+ 5. **What is the natural test** — every clause must be testable by a
85
+ black-box consumer. If you cannot write the test that fires when the
86
+ clause is violated, the clause is not contract-grade.
87
+ 6. **What is the cost of changing this in two years** — if the answer is
88
+ "trivial," it is probably not a contract clause. If the answer is
89
+ "every consumer rebuilds," that is exactly what a contract clause is
90
+ for and *exactly* why you write it down now.
91
+
92
+ If any answer is genuinely unknown, invoke the research pipeline — do not
93
+ guess. Guessing on §3.1 (consumers) creates contractual debt that surfaces
94
+ years later.
95
+
96
+ ---
97
+
98
+ ## 4. The error model — the single most copied-and-pasted contract clause
99
+
100
+ Most backend systems get error models wrong because they think of errors
101
+ as the unhappy path. They are not — they are *the consumer's API surface
102
+ under bad conditions*, and consumers depend on the shape exactly as much
103
+ as they depend on the success shape.
104
+
105
+ The error model Zadok fixes:
106
+
107
+ ```json
108
+ {
109
+ "error": {
110
+ "code": "resource_not_found",
111
+ "message": "Human-readable, safe for end-user display.",
112
+ "request_id": "req_01HX...",
113
+ "details": { "resource_type": "invoice", "resource_id": "in_..." }
114
+ }
115
+ }
116
+ ```
117
+
118
+ Rules:
119
+
120
+ - **`code` is stable.** It is the machine-readable identifier consumers
121
+ branch on. Once published, it never changes meaning. New codes are
122
+ additive; old codes survive forever.
123
+ - **`code` is `lowercase_snake_case`** and namespaced by domain
124
+ (`payment_failed`, not `failed`).
125
+ - **`message` is human-readable, safe to display, and may change.** It
126
+ is not contract — consumers must not match on it.
127
+ - **`request_id` is always present** on every error response, every
128
+ status, no exceptions. It is how support and the consumer correlate.
129
+ - **`details` is optional and free-form** but documented per `code`. If
130
+ you publish a `details` shape for a code, that shape becomes part of
131
+ the contract.
132
+ - **HTTP status maps to `code` consistently** but `code` carries more
133
+ information. 404 with `resource_not_found` is different from 404 with
134
+ `route_not_found`; the consumer needs the distinction.
135
+
136
+ The single most expensive mistake: shipping an API where errors are
137
+ free-text strings without codes. By the time consumers grep their logs
138
+ for `"not found"`, you cannot change the wording without breaking them.
139
+
140
+ ---
141
+
142
+ ## 5. Pagination — cursor or nothing
143
+
144
+ Offset pagination (`?page=3&page_size=20`) is conceptually simple and
145
+ broken in practice. Two failure modes are catastrophic:
146
+
147
+ - **Live data drift.** Items inserted/deleted between page reads cause
148
+ duplicates or skips. There is no fix at the server layer.
149
+ - **Deep paging cost.** `OFFSET 1000000` is a full scan in most databases.
150
+ Performance collapses past a few thousand pages.
151
+
152
+ The shape Zadok fixes:
153
+
154
+ ```json
155
+ {
156
+ "data": [...],
157
+ "next_cursor": "cur_01HX..." | null,
158
+ "has_more": true
159
+ }
160
+ ```
161
+
162
+ Cursor pagination is opaque-to-the-client by design. The cursor encodes
163
+ "where to resume" without leaking internals (it can be base64-encoded
164
+ `{last_id, last_sort_key}`, signed if you care about replay). It is
165
+ drift-safe and constant-cost.
166
+
167
+ If a consumer demands `total_count`, treat it as a separate, optional,
168
+ slow endpoint or a separate field with explicit caveats ("approximate,
169
+ recomputed periodically"). Do not couple it to the page response.
170
+
171
+ ---
172
+
173
+ ## 6. Naming — every name in the contract is load-bearing
174
+
175
+ Names in a contract are read in two contexts: by the consumer's IDE
176
+ autocomplete, and by the support engineer at 3am during an incident.
177
+ Both contexts favour names that are precise, consistent, and unambiguous.
178
+
179
+ Rules Zadok enforces:
180
+
181
+ - **One shape per concept across the API.** `customer_id` everywhere or
182
+ `customerId` everywhere; never mix. Pick one and apply it.
183
+ - **Verb-noun for actions, noun for resources.** `POST /invoices`
184
+ creates an invoice. `POST /invoices/{id}/void` is the action; the verb
185
+ is `void`, and it is on the action endpoint, not the resource endpoint.
186
+ - **Prefix identifiers by resource type.** `cus_01HX...`, `in_01HX...`.
187
+ Untyped identifiers (`01HX...`) make support and debugging twice as
188
+ hard. Stripe-style prefixes are not aesthetic — they are operational.
189
+ - **Booleans state what is true when set.** `is_active: true`, not
190
+ `inactive: false`. Double negatives in field names are a documented
191
+ source of consumer bugs.
192
+ - **Plural for collections, singular for resources.** `/invoices` lists,
193
+ `/invoices/{id}` is one. Never mix.
194
+ - **No abbreviations in names** unless they are universally understood
195
+ in the domain (`url`, `id`, `vat`). `addr`, `req`, `cust` are not
196
+ acceptable. The contract is read more often than it is typed.
197
+
198
+ ---
199
+
200
+ ## 7. Evolution — what counts as a breaking change
201
+
202
+ This is the rule that prevents the most damage in practice. Zadok's
203
+ working definition:
204
+
205
+ A change is **breaking** if any of the following would make a
206
+ correctly-coded existing consumer stop working:
207
+
208
+ 1. **Removing or renaming a field, endpoint, or error `code`.**
209
+ 2. **Tightening a constraint** — making a field required that was
210
+ optional; narrowing the allowed values of an enum; reducing a length
211
+ limit.
212
+ 3. **Changing the type of a field** (string → integer, integer → string)
213
+ or the shape of a nested object.
214
+ 4. **Changing the meaning of an existing field** while keeping its
215
+ name. The worst kind because it is silent.
216
+ 5. **Removing or tightening a guarantee** — webhook retry budget cut,
217
+ idempotency window reduced.
218
+ 6. **Changing the error `code` returned for a known scenario.**
219
+
220
+ A change is **non-breaking** if it is purely additive *and* default-safe:
221
+
222
+ - New endpoint.
223
+ - New optional field on a request (with a documented default).
224
+ - New field in a response (consumers must be told they may receive
225
+ unknown fields — a clause in the contract).
226
+ - New optional query parameter.
227
+ - New error `code` for a new scenario (existing scenarios keep their
228
+ existing code).
229
+ - Loosened constraint (longer maximum length, broader enum) — *for
230
+ responses;* tightening for requests is breaking, loosening is
231
+ non-breaking.
232
+
233
+ Two rules of thumb:
234
+
235
+ - **"It's just a small change" is the warning sign.** Every breaking
236
+ change someone justified with that phrase cost real money.
237
+ - **When in doubt, version.** A new version is a known cost. A silent
238
+ break is an unknown one.
239
+
240
+ ---
241
+
242
+ ## 8. Versioning — picking the shape that fits the consumer relationship
243
+
244
+ Three live patterns. Zadok picks the one that matches who consumes the API.
245
+
246
+ | Pattern | What it is | When to pick |
247
+ |---|---|---|
248
+ | **URL-versioned** (`/v1/`, `/v2/`) | major versions live side-by-side at different paths | external customers; long deprecation windows; multiple versions in production simultaneously |
249
+ | **Header-versioned** (`API-Version: 2026-05-01`) | versions selected by header; default version controlled centrally | external customers; you want one canonical path; willing to manage a default |
250
+ | **Single-version evolving API** | no version; only additive changes; breaking changes coordinated cross-team | internal-only; mono-repo; deploys coordinated |
251
+
252
+ Three rules:
253
+
254
+ - **Never mix.** Pick one and apply across the API.
255
+ - **Document the deprecation policy** as part of the contract. "Any
256
+ major version is supported for 18 months from the day a successor
257
+ ships." Without a policy, consumers assume forever and you are stuck.
258
+ - **Version on the contract level, not the implementation.** A v1
259
+ consumer can be served by a v2 implementation through translation;
260
+ the contract version is what the consumer sees.
261
+
262
+ ---
263
+
264
+ ## 9. Idempotency — when you promise it, fix the shape
265
+
266
+ Idempotency is a guarantee with a contract shape. If you offer it:
267
+
268
+ - **`Idempotency-Key` header.** Required for the endpoints that offer
269
+ the guarantee; ignored elsewhere. Client-supplied UUIDs (or any
270
+ unique string up to a documented length).
271
+ - **Window length is contractual.** "Idempotent over `Idempotency-Key`
272
+ for 24 hours." After the window, the key is forgotten and a re-issue
273
+ is a new operation.
274
+ - **Semantics on replay are contractual.** "On replay within the
275
+ window, return the original response with the original status." Not
276
+ "we will probably do the right thing."
277
+ - **Concurrent in-flight requests with the same key.** Either serialise
278
+ (later request waits) or reject with a specific code
279
+ (`idempotency_key_in_use`). Pick one and write it down.
280
+
281
+ The idempotency clause is the place where unstated guarantees most
282
+ often cause consumer bugs. The clause is short; the consequences of
283
+ omission are long.
284
+
285
+ ---
286
+
287
+ ## 10. Worked example A — "Should `customer.email` be required or optional?"
288
+
289
+ Situation: the customer model has an `email` field. PM wants it optional
290
+ to allow walk-in customers without email. Frontend lead wants it required
291
+ because the welcome flow assumes it.
292
+
293
+ Zadok's path:
294
+
295
+ **§3 answers extracted:**
296
+
297
+ 1. Consumers: web app, mobile app, partner integrations (external).
298
+ 2. Tightening (making it required later) breaks every existing
299
+ `POST /customers` that omitted it.
300
+ 3. Loosening (making it optional now) doesn't break the *server*, but
301
+ the welcome flow on the client breaks if email is missing.
302
+ 4. Invariant or guarantee: this is an invariant of the model.
303
+ 5. Testable: yes — POST without email succeeds (or fails) deterministically.
304
+ 6. Cost in two years: if optional → required later, every external
305
+ partner has to ship a fix. Major version step.
306
+
307
+ **Force tension named:** *consumer flexibility vs. server-side correctness*.
308
+
309
+ **Decision Zadok proposes:** `email` is **optional in the customer
310
+ resource** (the invariant), and the welcome-flow endpoint (the
311
+ *guarantee*) returns `error.code: missing_required_field` with
312
+ `details.field: email` if invoked on a customer whose email is unset.
313
+
314
+ The split: the resource model is permissive; the per-endpoint guarantee
315
+ is strict. This way the data model survives partner reality and the
316
+ welcome flow keeps its precondition explicit.
317
+
318
+ **ADR Out of Scope:** validating email format; deduplication on email;
319
+ GDPR retention. Each is its own decision.
320
+
321
+ **Trap rejected:** "We'll make it required for now and relax it later
322
+ if needed." Tightening later is a breaking change. Default to permissive
323
+ on data models, strict on action endpoints.
324
+
325
+ ---
326
+
327
+ ## 11. Worked example B — "The response shape needs `total_count`"
328
+
329
+ Situation: dashboard team needs `total_count` on the list-invoices
330
+ endpoint to show "3 of 47 results."
331
+
332
+ Zadok's path:
333
+
334
+ **§3 answers extracted:**
335
+
336
+ 1. Consumers: internal dashboard (single team); external Stripe-style
337
+ partners also use the endpoint.
338
+ 2. Adding `total_count` to the response: non-breaking (purely additive).
339
+ 3. The cost is server-side: `SELECT COUNT(*)` on a partitioned table at
340
+ 100k+ rows is not cheap; on 10M rows it is unacceptable.
341
+ 4. Invariant or guarantee: this is a guarantee on the list shape.
342
+ 5. Testable: yes.
343
+ 6. Cost in two years: if we ship `total_count` and the table grows, we
344
+ either accept slow lists or break the guarantee. Breaking it later is
345
+ contract-grade damage.
346
+
347
+ **Force tension named:** *consumer ergonomics vs. server cost at scale*.
348
+
349
+ **Decision Zadok proposes:** **Do not add `total_count` to the list
350
+ response.** Ship a separate `GET /invoices/count` endpoint that returns
351
+ an *approximate* count (`{ "approximate_count": 47, "as_of": "..." }`),
352
+ backed by a materialised view refreshed every minute. The contract
353
+ clause says "approximate," which means the consumer cannot rely on it
354
+ being exact — and the system cannot be forced into the slow path.
355
+
356
+ **The trap rejected:** the framing that "the dashboard team needs this
357
+ small field, so add it." A response field is a contract clause. Adding
358
+ one whose cost grows with data is a slow-motion incident waiting to
359
+ fire.
360
+
361
+ **Cross-team coordination:** Zadok flags this to Zerubbabel
362
+ (Yasad lead) before the contract decision lands — adding a new endpoint
363
+ is also Nathan's territory if it implies a new bounded context.
364
+
365
+ ---
366
+
367
+ ## 12. Writing CONTRACT.md — the shape
368
+
369
+ ```markdown
370
+ # CONTRACT — <Service Name>
371
+
372
+ > The promises this service makes to its consumers. Invariants are
373
+ > always true. Guarantees describe committed behaviour, often with bounds.
374
+
375
+ ## Versioning Policy
376
+
377
+ <URL-versioned / header-versioned / single-version evolving — pick one,
378
+ state deprecation window, state major-version policy>
379
+
380
+ ## Invariants
381
+
382
+ ### Identifiers
383
+ - All resource IDs are immutable for the life of the resource.
384
+ - IDs are prefixed by resource type: `<prefix>_<ulid>`.
385
+
386
+ ### Money
387
+ - Money fields are integer minor units (`amount_cents`).
388
+ - Currency is ISO 4217 alphabetic (`USD`, `EUR`), separate field.
389
+
390
+ ### Time
391
+ - Timestamps are RFC 3339 UTC, ending in `Z`.
392
+
393
+ ### Error Model
394
+ <the full error envelope shape; the rule that `code` is stable; the
395
+ rule that `message` is not contract>
396
+
397
+ ### Pagination
398
+ - List endpoints return ≤ 100 items per page.
399
+ - Pagination is cursor-based. `next_cursor` and `has_more` are returned.
400
+ - Offset pagination is not offered.
401
+
402
+ ### Naming
403
+ <the conventions from §6>
404
+
405
+ ## Guarantees
406
+
407
+ ### Idempotency
408
+ <which endpoints offer it, the window, the replay semantics, the
409
+ in-flight semantics>
410
+
411
+ ### Webhook Delivery
412
+ <retry budget, backoff schedule, drop policy, signature verification
413
+ contract>
414
+
415
+ ### Read-after-write
416
+ <which paths, which window, which consumer scope>
417
+
418
+ ## Evolution
419
+
420
+ - A change is breaking if any of: <§7 list>.
421
+ - Breaking changes require a new major version per the versioning policy above.
422
+ - New fields, endpoints, error codes, and optional parameters are
423
+ non-breaking and may ship in minor releases.
424
+
425
+ ## Conformance Tests
426
+
427
+ <reference to the test suite that exercises every clause from a black-
428
+ box consumer position>
429
+
430
+ ## Change Log of the Contract Itself
431
+
432
+ <dated entries for every contract change, including the kind:
433
+ clarification | addition | breaking change>
434
+ ```
435
+
436
+ The Change Log of the contract itself matters more than people expect.
437
+ It is how a consumer trying to debug a six-month-old integration knows
438
+ whether the API changed under them.
439
+
440
+ ---
441
+
442
+ ## 13. The interface with Hizkiah, Nathan, Zerubbabel
443
+
444
+ - **Zadok → Hizkiah.** Zadok fixes the contract; Hizkiah implements
445
+ against it. If Hizkiah finds the contract under-specified mid-
446
+ implementation, Hizkiah stops and surfaces — does not "fill in the
447
+ gap." Gap-filling unilaterally is how contracts diverge from
448
+ implementations.
449
+ - **Nathan → Zadok.** Nathan's architecture decisions shape the
450
+ contract surface (which bounded contexts exist, where the seams
451
+ are). Zadok writes the consumer-facing rules within those seams.
452
+ - **Zerubbabel → Zadok.** Zerubbabel routes contract decisions and
453
+ signs off on shape questions. Zadok proposes; Zerubbabel ratifies.
454
+ - **Mishmar → Zadok.** Mishmar reviews the contract for security-
455
+ sensitive clauses (auth scopes, rate limits, secret-handling, audit-
456
+ log shape). Zadok holds the pen; Mishmar holds the veto on the
457
+ security-relevant clauses.
458
+
459
+ ---
460
+
461
+ ## 14. The recurring traps Zadok rejects on sight
462
+
463
+ 1. **"This field is internal so it doesn't need to be documented."**
464
+ Anything that crosses the service boundary is contract. Internal
465
+ shapes that leak into a public response become contract by accident
466
+ on the first consumer that depends on them. Either redact at the
467
+ boundary or document.
468
+
469
+ 2. **"We'll just add a feature flag."** Feature flags are not contract
470
+ versions. A flag-gated behaviour change is still a behaviour change;
471
+ consumers without the flag get one contract, consumers with it get
472
+ another. If consumers can observe the flag, it is contract surface.
473
+
474
+ 3. **"It's optional, so we can change it later."** Optional fields are
475
+ contract. Removing an optional field is breaking. The "optional"
476
+ suffix is about request shape, not contract durability.
477
+
478
+ 4. **"Errors don't need codes; the message is enough."** §4 in full.
479
+ This is the single trap with the largest historical cost.
480
+
481
+ 5. **"`total_count` is trivial to add."** §11 worked example.
482
+
483
+ 6. **"We don't need an idempotency window — clients will be careful."**
484
+ No, they will not. Either offer idempotency with a stated window or
485
+ do not offer it at all. "Probably idempotent" is worse than "not
486
+ idempotent."
487
+
488
+ 7. **"Just expose the database column."** ORM-shaped responses leak
489
+ schema, force naming changes to ripple through the contract, and
490
+ couple consumers to internal storage. Always project to a contract
491
+ shape; never publish the raw row.
492
+
493
+ ---
494
+
495
+ ## 15. Style — Zadok's working voice
496
+
497
+ - **Present tense, declarative.** "The system promises X."
498
+ Not "the system will promise X."
499
+ - **Numeric where possible.** "≤ 100 items per page." Not "a reasonable
500
+ number." A reasonable-number-of-items is everyone's least favourite
501
+ bug.
502
+ - **No weasel words.** "Probably," "usually," "in most cases" do not
503
+ belong in a contract. If a clause is conditional, the condition is
504
+ part of the clause.
505
+ - **Plain refusal where needed.** "We do not offer this." Better than
506
+ "we don't currently plan to support this," which is consumed as "we
507
+ will support this later."
508
+ - **Same care a high priest gives the standards across generations.**
509
+ Names are righteousness — sloppy names are how injustice sneaks in.
510
+ This is not metaphor; it is operational.
511
+
512
+ ---
513
+
514
+ *Cross-references: `~/.claude/rules/y4nn-standards.md`
515
+ (sequence rule §1, durable rule §3, no-fabrication rule §6,
516
+ explanation-before-action rule §7, naming rule §11),
517
+ `payload/mishkan/agents/zadok.md` (the agent that invokes this skill),
518
+ `payload/mishkan/skills/nathan-architecture-craft/SKILL.md` (when the
519
+ contract decision is also an architecture decision; both skills are
520
+ invoked in tandem).*
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "mishkan://templates/case-node.schema.json",
4
+ "title": "MISHKAN Case Node",
5
+ "description": "Written to Cognee when an agent solves a problem using a curated resource (design §8).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["type", "team", "agent", "problem_class", "resource_applied", "resolution", "outcome", "sprint", "task"],
9
+ "properties": {
10
+ "type": { "const": "case" },
11
+ "team": { "type": "string" },
12
+ "agent": { "type": "string" },
13
+ "problem_class": { "type": "string", "description": "Generalised class of problem, not the specific instance" },
14
+ "resource_applied": { "type": "string", "description": "Curated resource identifier or URL" },
15
+ "resolution": { "type": "string", "description": "What resolved it" },
16
+ "outcome": { "type": "string", "enum": ["resolved", "partial", "blocked"] },
17
+ "sprint": { "type": "string", "pattern": "^S[0-9]+$" },
18
+ "task": { "type": "string", "pattern": "^T-[0-9]+$" },
19
+ "blast_radius": { "type": "string", "enum": ["team-level", "cross-harness"], "default": "team-level" },
20
+ "timestamp": { "type": "string", "format": "date-time" }
21
+ }
22
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "_comment": "MISHKAN MCP template. /mishkan-init copies this to the project root as .mcp.json. TWO physically-separate cognee stores: 'cognee' = the WORK box (this project's own knowledge graph, read+write; mishkan-cognee-* on :7777) and 'cognee-curated' = the shared CURATED reference library (read-mostly, isolated graph; mishkan-curated-* on :7730). Project knowledge and the curated library never mix (decision D-007). Both run from ~/.claude/mishkan/cognee/. For the zero-container stdio alternative, replace an entry with the _stdio_alternative block (set the absolute path to a cloned cognee-mcp and LLM_API_KEY). Refs: https://docs.cognee.ai/cognee-mcp/mcp-local-setup",
3
+ "mcpServers": {
4
+ "cognee": {
5
+ "type": "http",
6
+ "url": "http://localhost:7777/mcp"
7
+ },
8
+ "cognee-curated": {
9
+ "type": "http",
10
+ "url": "http://localhost:7730/mcp"
11
+ }
12
+ },
13
+ "_stdio_alternative": {
14
+ "cognee": {
15
+ "command": "uv",
16
+ "args": ["--directory", "/absolute/path/to/cognee/cognee-mcp", "run", "cognee-mcp"],
17
+ "env": {
18
+ "LLM_API_KEY": "${LLM_API_KEY}"
19
+ }
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "mishkan://templates/observability-log.schema.json",
4
+ "title": "MISHKAN Observability Log Entry",
5
+ "description": "One entry per agent tool call, emitted by the PostToolUse hook (design §10).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["agent", "team", "sprint", "session", "tool_calls", "outcome", "timestamp"],
9
+ "properties": {
10
+ "agent": { "type": "string" },
11
+ "team": { "type": "string" },
12
+ "sprint": { "type": "string", "pattern": "^S[0-9]+$" },
13
+ "session": { "type": "string", "description": "Session ID" },
14
+ "tool_calls": { "type": "array", "items": { "type": "string" } },
15
+ "tokens_input": { "type": "integer", "minimum": 0, "default": 0 },
16
+ "tokens_cached": { "type": "integer", "minimum": 0, "default": 0 },
17
+ "tokens_output": { "type": "integer", "minimum": 0, "default": 0 },
18
+ "cost": { "type": "number", "minimum": 0, "default": 0 },
19
+ "model_tier": { "type": "string", "enum": ["opus", "sonnet", "haiku"] },
20
+ "outcome": { "type": "string", "enum": ["completed", "blocked", "escalated"] },
21
+ "cognee_writes": { "type": "integer", "minimum": 0, "default": 0 },
22
+ "timestamp": { "type": "string", "format": "date-time" }
23
+ }
24
+ }
@@ -0,0 +1,47 @@
1
+ # {{PROJECT_NAME}} — Project State
2
+
3
+ > Seeded by `/mishkan-init`. This is the lean, dynamic project state artifact.
4
+ > It loads after the user-level harness identity and is injected last (after the
5
+ > cached static prefix) so sprint state stays at the end of context.
6
+
7
+ ## Project
8
+
9
+ - **Name:** {{PROJECT_NAME}}
10
+ - **Stack:** {{STACK}}
11
+ - **Cognee namespace:** {{COGNEE_NAMESPACE}}
12
+ - **Initialised:** {{DATE}}
13
+
14
+ ## Design artifacts (in `docs/`)
15
+
16
+ - `docs/PRD.md` — product requirements
17
+ - `docs/SRS.md` — software requirements
18
+ - `docs/CONTRACT.md` — invariants + guarantees
19
+ - `docs/ARCHITECTURE.md` — system architecture
20
+ - `docs/THREAT_MODEL.md` — security threat model
21
+ - `docs/diagrams/C4/` — C4 diagrams
22
+ - `docs/adr/` — architecture decision records
23
+ - `docs/runbooks/` — operational runbooks
24
+
25
+ ## Current sprint
26
+
27
+ - **Sprint:** {{SPRINT}}
28
+ - **Milestone:** {{MILESTONE}}
29
+ - **Mode:** {{MODE}}
30
+
31
+ ### Tasks
32
+
33
+ <!-- maintained by Nehemiah; conforms to sprint-state.schema.json -->
34
+ {{TASKS}}
35
+
36
+ ### Blockers
37
+
38
+ <!-- raised by any agent; Mishmar flags carry highest priority -->
39
+ {{BLOCKERS}}
40
+
41
+ ### Open flags
42
+
43
+ {{FLAGS}}
44
+
45
+ ---
46
+
47
+ *Updated at milestones by Nehemiah. Mirrored to Cognee. Restored by `/mishkan-resume`.*
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "mishkan://templates/research-log.schema.json",
4
+ "title": "MISHKAN Research Log Entry",
5
+ "description": "Contract produced by any agent invoking the research pipeline (design §14).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "agent",
10
+ "team",
11
+ "sprint",
12
+ "trigger",
13
+ "query_intent",
14
+ "tools_invoked",
15
+ "research_output_summary",
16
+ "applied_to_task",
17
+ "outcome",
18
+ "knowledge_graph_write",
19
+ "curated_library_match"
20
+ ],
21
+ "properties": {
22
+ "agent": { "type": "string", "description": "Alias of the calling agent" },
23
+ "team": { "type": "string", "description": "Team name or 'orchestration' / 'research'" },
24
+ "sprint": { "type": "string", "pattern": "^S[0-9]+$" },
25
+ "trigger": { "type": "string", "enum": ["faced_problem", "requested"] },
26
+ "query_intent": { "type": "string", "description": "What the agent was trying to find out" },
27
+ "tools_invoked": {
28
+ "type": "array",
29
+ "items": { "type": "string" },
30
+ "description": "Pipeline agents/tools used (Jakin, Ezra, Caleb, Shaphan, Shemaiah, Baruch)"
31
+ },
32
+ "research_output_summary": { "type": "string", "description": "Compressed result. Full output lives in Cognee." },
33
+ "applied_to_task": { "type": "string", "description": "Task reference (T-N) or 'exploration'" },
34
+ "outcome": { "type": "string", "enum": ["resolved", "partial", "blocked"] },
35
+ "knowledge_graph_write": { "type": "boolean", "description": "Was a Cognee node written" },
36
+ "curated_library_match": { "type": "boolean", "description": "True if solved via curated library, not web pipeline" },
37
+ "cognee_node_id": { "type": ["string", "null"], "description": "ID of the written Cognee node, if any" },
38
+ "timestamp": { "type": "string", "format": "date-time" }
39
+ }
40
+ }