@r1z4x/tezgah 1.6.0 → 1.7.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 (64) hide show
  1. package/CHANGELOG.md +80 -1
  2. package/MANIFEST +5 -0
  3. package/README.md +6 -3
  4. package/bin/tezgah-docs +18 -16
  5. package/bin/tezgah-doctor +152 -0
  6. package/bin/tezgah-research +234 -10
  7. package/bin/tezgah-route +48 -1
  8. package/bin/tezgah-setup +26 -13
  9. package/bin/tezgah-task +589 -17
  10. package/bin/tezgah-taste +48 -10
  11. package/docs/architecture.md +7 -4
  12. package/docs/clarity-baseline.json +2 -2
  13. package/docs/contract.md +108 -24
  14. package/docs/evidence.md +201 -28
  15. package/docs/feature-audit.md +1 -1
  16. package/docs/gate.md +60 -22
  17. package/docs/glossary.md +4 -4
  18. package/docs/hosts.md +8 -8
  19. package/docs/index.json +11 -5
  20. package/docs/judge.md +9 -3
  21. package/docs/models.md +35 -2
  22. package/docs/operations.md +103 -3
  23. package/docs/research.md +346 -13
  24. package/docs/skills.md +1 -1
  25. package/docs/status-line.md +5 -5
  26. package/docs/testing.md +2 -2
  27. package/docs/vision.md +12 -4
  28. package/hooks/hooks.json +2 -2
  29. package/hooks/lang/en.json +323 -0
  30. package/hooks/lang/tr.json +344 -0
  31. package/hooks/projects-posttooluse.py +24 -5
  32. package/hooks/projects-pretooluse.py +9 -4
  33. package/hooks/projects-stop.py +28 -16
  34. package/hooks/tezgah_agents.py +29 -10
  35. package/hooks/tezgah_clarity.py +7 -3
  36. package/hooks/tezgah_context.py +425 -406
  37. package/hooks/tezgah_gate.py +583 -33
  38. package/hooks/tezgah_integrity.py +1480 -197
  39. package/hooks/tezgah_models.py +337 -15
  40. package/hooks/tezgah_paths.py +103 -10
  41. package/hooks/tezgah_policy.py +258 -126
  42. package/hooks/tezgah_rank.py +29 -27
  43. package/hooks/tezgah_replay.py +200 -30
  44. package/hooks/tezgah_research.py +1294 -9
  45. package/hooks/tezgah_stopspec.py +7 -0
  46. package/hooks/tezgah_store.py +74 -27
  47. package/hooks/tezgah_task.py +915 -6
  48. package/hosts/codex/hook.py +9 -10
  49. package/hosts/cursor/hook.py +21 -14
  50. package/hosts/dsh/hooks.json +2 -2
  51. package/hosts/omp/hook.py +44 -23
  52. package/hosts/omp/tezgah-hook.ts.in +93 -7
  53. package/hosts/opencode/plugins/tezgah.js +102 -2
  54. package/output-styles/tezgah.md +76 -42
  55. package/package.json +1 -1
  56. package/skills/i-have-adhd/EVALS.md +22 -2
  57. package/skills/i-have-adhd/SKILL.md +12 -5
  58. package/skills/plan-add/SKILL.md +5 -3
  59. package/skills/plan-sync/SKILL.md +5 -3
  60. package/skills/ponytail/EVALS.md +21 -2
  61. package/skills/ponytail/SKILL.md +4 -4
  62. package/skills/research/SKILL.md +89 -1
  63. package/skills/tezgah-contract/EVALS.md +52 -7
  64. package/skills/tezgah-contract/SKILL.md +151 -56
@@ -0,0 +1,344 @@
1
+ {
2
+ "name": "Turkish",
3
+ "done": [
4
+ "yaptım|tamamladım|tamamlandı|bitirdim|bitirildi|ekledim|eklendi|düzelttim|düzeltildi|hallettim|güncellendi|kuruldu|uygulandı|yayına girdi|kapatıldı|yüklendi|tüm testler geçti|testler geçti|testler yeşil|çalışıyor"
5
+ ],
6
+ "verified": [
7
+ "doğruladım|test ettim|kontrol ettim|denetledim|doğrulandı|test edildi"
8
+ ],
9
+ "negated": [
10
+ "doğrulanmadı|doğrulamadım|kontrol edilmedi|test edilmedi"
11
+ ],
12
+ "admitted": [
13
+ "çeliş|geçemez|imk[aâ]nsız"
14
+ ],
15
+ "sycophant": {
16
+ "interjection": [
17
+ "evet"
18
+ ],
19
+ "opener": [
20
+ "haklısın|haklısınız|iyi yakaladın|detaylı bakmadım"
21
+ ]
22
+ },
23
+ "closer": [],
24
+ "next_action": [
25
+ "sıradaki adım|sonraki adım"
26
+ ],
27
+ "preamble": [
28
+ "aşağıda|şöyle\\b|öncelikle\\b|şimdi\\b"
29
+ ],
30
+ "markers": {
31
+ "letters": [
32
+ "ç",
33
+ "ğ",
34
+ "ı",
35
+ "ö",
36
+ "ş",
37
+ "ü",
38
+ "Ç",
39
+ "Ğ",
40
+ "İ",
41
+ "Ö",
42
+ "Ş",
43
+ "Ü"
44
+ ],
45
+ "words": [
46
+ "ve",
47
+ "bir",
48
+ "bu",
49
+ "şu",
50
+ "için",
51
+ "ile",
52
+ "ama",
53
+ "fakat",
54
+ "veya",
55
+ "mı",
56
+ "mu",
57
+ "mü",
58
+ "çok",
59
+ "daha",
60
+ "gibi",
61
+ "kadar",
62
+ "sonra",
63
+ "önce",
64
+ "var",
65
+ "yok",
66
+ "değil",
67
+ "olarak",
68
+ "olan",
69
+ "hem",
70
+ "ise",
71
+ "ki",
72
+ "artık",
73
+ "hâlâ",
74
+ "hala",
75
+ "şimdi",
76
+ "yani",
77
+ "diye",
78
+ "tüm",
79
+ "bütün",
80
+ "kalan",
81
+ "neden",
82
+ "nasıl",
83
+ "yeni",
84
+ "eski",
85
+ "evet",
86
+ "hayır"
87
+ ]
88
+ },
89
+ "negation_before": [
90
+ "\\bdeğil"
91
+ ],
92
+ "question_particle": [
93
+ "m[ıiuü]|değil"
94
+ ],
95
+ "question_end": [
96
+ "m[ıiuü]"
97
+ ],
98
+ "clause_join": [
99
+ "ama|ve"
100
+ ],
101
+ "external_state": [
102
+ "yok|eksik|yayımlan|yayınlan"
103
+ ],
104
+ "external_ci_state": [
105
+ "geçti|başarısız"
106
+ ],
107
+ "publish_state": [
108
+ "yok|eksik|yayımlan|yayınlan"
109
+ ],
110
+ "residual_label": [
111
+ "açık (?:kalan|iş|madde|nokta|soru)|eksik(?!siz)|yapılama|yapılma(?:yan|dı)|yapılacak|bekleyen|bakıla?ma|bitme(?:yen|di)|tamamlanma|kısmen|doğrulan(?:a)?ma|test edile?me|çalıştırıla?ma|koşula?ma|dokunula?ma|sonraki adım|sıradaki|sırada\\b|kapsam dışı|atlan(?:an|dı)|ertelen|bilinen (?:hata|sınırlama|sorun)|teknik borç|ileride|gelecek (?:iş|çalışma)|önerilen (?:iyileştirme|adım)|manuel doğrulama|elle doğrula|engel(?:ler)?\\b|engelleyenler\\b|erişilemeyen|fix-?later|\\w+m[ae]d[ıiuü](?:m|kl[ae]r(?:[ıi]m)?)\\b|kontrol edil(?:e)?me|incelen(?:e)?me|ölçül(?:e)?me|çözül(?:e)?me|denen(?:e)?me|ulaşılama|(?:yarım|askıda|sonraya) kalan|sonra bakılacak"
112
+ ],
113
+ "residual_first": [
114
+ "kalan(?:lar)?(?=\\s*(?:\\(|$))|kalan\\s+(?:tek\\s+)?(?:iş|işler|adım|adımlar|madde|maddeler|görev|görevler|şey)\\b"
115
+ ],
116
+ "label_done": [
117
+ "giderildi|çözüldü|yazıldı|bitti|ölçüldü|yapıldı|halledildi|kapandı|kalmadı|tamamlanan|düzeltilen|giderilen|kapatılan|çözülen|artık (?:var|mevcut)"
118
+ ],
119
+ "partial": [
120
+ "kısmen"
121
+ ],
122
+ "nothing_left": [
123
+ "\\byok"
124
+ ],
125
+ "nothing_lead": [],
126
+ "empty_item": [
127
+ "yok|hiç(?:biri|bir şey)?"
128
+ ],
129
+ "blockers": {
130
+ "decision": {
131
+ "pattern": "KARAR"
132
+ },
133
+ "irreversible": {
134
+ "pattern": "GER[İI] ALINAMAZ"
135
+ },
136
+ "access": {
137
+ "pattern": "YETK[İI][A-ZÇĞİIÖŞÜ]*"
138
+ },
139
+ "env": {
140
+ "pattern": "ORTAM[A-ZÇĞİIÖŞÜ]*"
141
+ },
142
+ "said_not": [
143
+ "gerek(?:mi|mez|tirm|li\\s+değil)|istem|yok\\b|değil\\b"
144
+ ],
145
+ "tried_not": [
146
+ "değil\\b|gerek(?:mi|mez|tirm)|istem"
147
+ ],
148
+ "absent": [
149
+ "yok"
150
+ ]
151
+ },
152
+ "blocker_labels": [
153
+ "engel"
154
+ ],
155
+ "blockers_only": [
156
+ "engel(?:ler)?"
157
+ ],
158
+ "env_error": [
159
+ "bulunamad|kurulu değil|yüklü değil|mevcut değil"
160
+ ],
161
+ "access_error": [
162
+ "izin|reddedil|erişim"
163
+ ],
164
+ "spawn_words": [
165
+ "ajan|sağlayıcı"
166
+ ],
167
+ "was_exclude": [
168
+ "şimdi|kendi|ileri|geri"
169
+ ],
170
+ "was": [
171
+ "\\w+(?<!m[ae])(?:yordu|[dt][ıiuü])"
172
+ ],
173
+ "now": [
174
+ "^artık\\b.*(?:\\bvar\\b|\\bmevcut\\b|\\w+yor\\b)"
175
+ ],
176
+ "future": [
177
+ "\\w+(?:acak|ecek)"
178
+ ],
179
+ "word_order": "object_first",
180
+ "ui_objects": [
181
+ "akış|adım|ekran|sayfa|arayüz|form|menü|buton|düğme|panel|tasarım|görünüm|kart|bileşen|sekme|pencere"
182
+ ],
183
+ "ui_quality": [],
184
+ "hints": {
185
+ "spec": [
186
+ "düzgün çalış\\w*|düzgün görün\\w*|güzel görün\\w*|daha iyi (ol|görün)\\w*|kullanıcı dostu|modern görün\\w*|şık (ol|görün)\\w*|profesyonel görün\\w*|temiz (bir )?(arayüz|görün)\\w*|anlaşılır\\w*|kullanılabilirlik\\w*",
187
+ {
188
+ "ui_ask": "basitleştir\\w*|sadeleştir\\w*"
189
+ },
190
+ "yeniden tasarla\\w*|baştan tasarla\\w*|tasarım\\w*|focus[- ]durum\\w*|tipografi\\w*|bileşen\\w*|tema\\w*|animasyon\\w*|erişilebilir\\w*|prototip\\w*|hizala\\w*|hiza\\w*|boşluk\\w*|satır aral\\w*|gölge\\w*|kenarlık\\w*|yazı tipi\\w*|punto\\w*|renk\\w*|palet\\w*|devre dışı\\w*|boş durum\\w*|kırılma nokta\\w*|mobil (uyumlu|görünüm)|karanlık mod\\w*|aydınlık mod\\w*|renk şema\\w*|stil rehber\\w*|tasarım sistemi|tasarım token\\w*|ekran okuyucu\\w*|kontrast\\w*|ekran görüntü\\w*|görsel (incele|kontrol|karşılaştır)\\w*"
191
+ ],
192
+ "consult": [
193
+ "mimari\\w*|kök neden\\w*|geri dönüşü olmayan|kırıcı değişiklik\\w*|geriye dönük uyum\\w*|api sürüm\\w*|sürümleme\\w*|versiyonlama\\w*|şema\\w*|göç\\w*|migrasyon\\w*|veri (taşı|göç)\\w*|geri al\\w*|geri (alınamaz|dönüşü (yok|olmaz|olmayan))|performans bütçe\\w*|gecikme bütçe\\w*|güvenlik\\w*|zafiyet\\w*|bağımlılık(ları)? güncelle\\w*|paket güncelle\\w*|sürüm yükselt\\w*|tedarik zincir\\w*|eş ?zamanlı\\w*|yarış (durumu|koşulu)\\w*|kapasite (plan|hesab|test|sınır)\\w*|ölçeklen\\w*|yük test\\w*|mimari karar\\w*|tasarım karar\\w*|politika değiş\\w*|sözleşme (değiş|yenile)\\w*|yayına al\\w*|canlıya al\\w*|sürüm çıkar\\w*|ödün (ver|vermey)\\w*"
194
+ ],
195
+ "research": [
196
+ "araştır\\w*|literatür\\w*|hipotez\\w*|deney|karşılaştır\\w*|karşılaştırmalı analiz|kıyaslama\\w*|varyant\\w*|a/b testi|(kullanıcı|müşteri) (interview\\w*|görüşme\\w*|mülakat\\w*)|user (görüşme\\w*|mülakat\\w*)|anket\\w*|kök neden (analiz|araştır)\\w*|kaynak tarama\\w*|referans tarama\\w*|(yöntem|yaklaşım|kütüphane|varyant|seçenek)\\w* karşılaştır\\w*|ölçüm\\w*|deneysel\\w*|deneyler\\w*|makale\\w*|veri (seti|kümesi)|olay sonrası (analiz|değerlendirme)\\w*|hata bütçe\\w*|gerçekten (doğru|öyle) mu|kanıt\\w*|test kapsam\\w*|kapsam oran\\w*|kapsamı (artır|yükselt)\\w*|doküman(tasyon)?\\w* (yetersiz|eksik|kötü|zayıf)"
197
+ ],
198
+ "product": [
199
+ "ürün\\w*|yol harita\\w*|kuzey yıldız\\w*|aktivasyon\\w*|dönüşüm\\w*|fiyatlandır\\w*|önceliklendir\\w*|kullanıcı araştırma\\w*|ürün keşf\\w*|müşteri geri bildirim\\w*|benimsen\\w*|konumlandır\\w*|segmentasyon\\w*|hedef kitle\\w*|(kullanıcı|müşteri) discovery|keşif (görüşme|çalışma)\\w*|fırsat\\w*|memnuniyet\\w*|anket\\w*|(kullanıcı|müşteri)[ -]?(feedback|geri bildirim)\\w*|(customer|user)[ -]?geri bildirim\\w*|şikayet\\w*|rakip\\w*|rekabet\\w*|pazar pay\\w*|terk oran\\w*|elde tutma\\w*|abonelik\\w*|gelir model\\w*|özellik\\w*|sayfa(?! numara)\\w*|ekran(?! kart)(?!a\\b[^.!?\\n]{0,40}\\b(?:yaz|bas)\\w*)\\w*|arayüz\\w*|arama kutu\\w*|filtre\\w*|tablo(?![^.!?\\n]{0,60}\\b(?:sütun|kolon|sql|index|indeks)\\w*)\\w*|adım(?! sayı)\\w*|kullanıcı liste\\w*|form(u|un|da|daki|lar|ları|unu)\\w*"
200
+ ],
201
+ "graph": [
202
+ "kim çağır\\w*|çağrı yerleri|nerede tanımlı|nasıl bağlan\\w*|etkilenir\\w*|hangi dosyalar etkilen\\w*|etki (analiz|alan)\\w*|neyi etkile\\w*|neleri etkile\\w*|etkilen\\w*|bağımlı\\w*|kullanılmayan\\w*|kullanılmıyor|ölü kod|döngüsel (bağımlılık|import)\\w*|giriş nokta\\w*|uygulama (nerede|nereden) başl\\w*|kim import ed\\w*|(fonksiyon|metod|sınıf|modül|api)\\w* (kim|nerede) kullan\\w*|nerede (kullanıl|çağrıl)\\w*|tanım\\w* nerede|kullanım yerleri|çağrı (zinciri|grafiği)|bağımlılık (grafiği|ağacı)|yeniden adlandır\\w*"
203
+ ]
204
+ },
205
+ "fan_verbs": [
206
+ "düzelt|güncelle|ekle|yaz|sil|kaldır|taşı|bitir|tamamla|incele|oluştur|değiştir"
207
+ ],
208
+ "fan_join": [
209
+ "ve"
210
+ ],
211
+ "fan_ordinals": [
212
+ "birinci(?:si)?",
213
+ "ikinci(?:si)?"
214
+ ],
215
+ "fan_directives": [
216
+ "paralel\\w*|alt ?ajan\\w*|orkestra\\w*"
217
+ ],
218
+ "data_ask": [
219
+ "(?:metri[ck]s?|kpis?|data|sales|revenue) (?:\\w+ ){0,2}pano|(?:veri\\w*|satış\\w*|gelir\\w*) (?:\\w+ ){0,2}(?:dashboard|pano)|(?:dashboard|gösterge panel)\\w* (?:\\w+ ){0,4}(?:tasarla|oluştur|hazırla|yap|göster)\\w*|öner\\w* (?:\\w+ ){0,3}grafi\\w*|hangi (?:metri[ck]\\w*|kpi\\w*|grafi\\w*|göstergeleri?)|(?:metri[ck]\\w*|kpi\\w*) (?:\\w+ ){0,3}(?:tasarla|seç|tanımla|belirle|takip|izle)\\w*|gösterge panel\\w*|visuali[sz]\\w* (?:\\w+ ){0,3}veri\\w*|veri\\w* (?:\\w+ ){0,3}görselleştir\\w*"
220
+ ],
221
+ "code_sense": [
222
+ "\\b(?:indeks\\w*|veri yapı\\w*|fonksiyon\\w*|bileşen\\w*|modül\\w*|dosya\\w*|kopyala\\w*|seçici\\w*|yükleme|ilerleme|paket\\w*)\\b"
223
+ ],
224
+ "constraint": {
225
+ "dont": [
226
+ "(?P<obj>[\\w./@~-]+?)(?:'\\w+)?\\s+(?:sakın\\s+)?dokunma(?:yın|yınız)?\\b(?!\\s+(?:hedef|alan|olay|duyar)\\w*)"
227
+ ],
228
+ "ask": [
229
+ "(?:bana\\s+)?sormadan\\s+(?P<ask>\\w+)\\s+(?:etme|yapma)\\w*"
230
+ ],
231
+ "grant": [
232
+ "(?:bana\\s+)?sormadan(?!\\s+(?:\\w+\\s+)?(?:etme|yapma|ilerleme|gitme)\\w*)|onay(?:ı|ımı)?\\s+ver(?:iyorum|dim)|izin\\s+ver(?:iyorum|dim)|onaylıyorum|sormana gerek yok"
233
+ ],
234
+ "lift": [
235
+ "(?:artık|bundan sonra|tekrar|yine)\\s+(?:bana\\s+)?sor\\b|onay\\w*\\s+geri\\s+al\\w*|izn\\w*\\s+geri\\s+al\\w*"
236
+ ],
237
+ "lift_outward": [
238
+ "(?:pr\\b|push\\w*|release\\w*|yayınla\\w*|yayımla\\w*|sürüm\\b|versiyonla\\w*|etiketle\\w*|tag\\w*)(?:\\s+\\S+){0,2}?\\s+(?:et|yap|çıkar)(?:ma|me)(?:y[ıi]n\\w*)?\\b",
239
+ "(?:push|yay[ıi]nla|yayımla|etiketle|versiyonla|tag)(?:la|le)?m[ae](?:y[ıi]n\\w*)?\\b"
240
+ ],
241
+ "grant_not": [
242
+ "\\b(?!bütün\\b)\\w+[dt][ıiuü]n(?:[ıi]z)?\\b|\\bneden\\b|\\bniye\\b"
243
+ ],
244
+ "grant_not_verb": [
245
+ "\\w{2,}m[ae](?:y[ıi]n(?:[ıi]z)?)?"
246
+ ],
247
+ "grant_not_soft": [
248
+ "durma|bekleme|sorma|unutma"
249
+ ]
250
+ },
251
+ "ask": {
252
+ "process": [
253
+ "\\b(?:başlayayım|devam edeyim|ilerleyeyim|geçeyim|sürdüreyim|uygulayayım|yapayım|açayım|kapatayım|birleştireyim|merge edeyim|commit(?:le)?(?:yeyim|eyim| atayım)|koşayım|çalıştırayım)\\b|\\b(?:devam etmemi|başlamamı|ilerlememi|commit atmamı|merge etmemi|uygulamamı|yapmamı) ister mis\\w*|\\bhangisi(?:nden|yle|ni)? (?:önce|ile başla|başla\\w*)|\\bnereden başla\\w*"
254
+ ],
255
+ "never_default": [
256
+ "zorla|geçmiş\\w* (?:yeniden yaz|değiştir)\\w*|\\bsil\\w*|kaldır\\w*|yok et\\w*|üretim\\w*|\\bcanlı\\w*|\\bprod\\w*|göç\\w*|kimlik bilgi\\w*|şifre\\w*|parola\\w*|\\bhesa[bp]\\w*|e-?posta\\w*|gönder\\w*"
257
+ ],
258
+ "spend": [
259
+ "ücret\\w*|ödeme\\w*|harca\\w*|bütçe\\w*|maliyet\\w*|\\bpara\\b|dolar\\w*|\\$\\s?\\d"
260
+ ],
261
+ "default_mark": [
262
+ "öneri\\w*|önerilen|önerim|varsayılan\\w*|tavsiye\\w*"
263
+ ],
264
+ "options": [
265
+ "\\bveya\\b|\\bya da\\b|\\byoksa\\b|seçenek\\w*|alternatif\\w*|\\bm[ıiuü]\\b.+\\bm[ıiuü]\\b|\\b(?:a|1)\\)?\\s.+?,\\s*(?:b|2)\\)?\\s"
266
+ ],
267
+ "cheap_answer": [
268
+ "evet|tamam|olur|devam(?: et)?|yap|başla|ilerle|okey|onay(?:lıyorum)?"
269
+ ],
270
+ "outward": {
271
+ "push": "\\bpush\\w*",
272
+ "release": "versiyon\\w*|sürüm\\w*|\\brelease\\w*|etiket\\w*",
273
+ "publish": "yayınla\\w*|yayımla\\w*|\\bnpm\\b|homebrew",
274
+ "pr": "\\bpr\\b|pull request"
275
+ }
276
+ },
277
+ "needle_stop": [
278
+ "ve",
279
+ "veya",
280
+ "ile"
281
+ ],
282
+ "rank_stopwords": [
283
+ "bir",
284
+ "bunu",
285
+ "buna",
286
+ "bunlar",
287
+ "şunu",
288
+ "için",
289
+ "ile",
290
+ "ama",
291
+ "gibi",
292
+ "daha",
293
+ "çok",
294
+ "kadar",
295
+ "veya",
296
+ "değil",
297
+ "her",
298
+ "hem",
299
+ "olan",
300
+ "olarak",
301
+ "sonra",
302
+ "önce",
303
+ "ise",
304
+ "yani",
305
+ "nasil",
306
+ "neden"
307
+ ],
308
+ "fold": [
309
+ "ıi",
310
+ "âa",
311
+ "îi",
312
+ "ûu"
313
+ ],
314
+ "say": {
315
+ "unverified": "doğrulanmadı",
316
+ "reply_lang": "Turkish",
317
+ "reply_in": "in Turkish, even when the user\nwrites English",
318
+ "reply_split": "in Turkish, ALWAYS, even when the user writes English",
319
+ "reply_short": "reply Turkish",
320
+ "gap_example": "\"deploy öncesi doğrulamadım; riski şöyle değerlendirdim: ...\"",
321
+ "blocker_tokens": "KARAR, YETKİ, GERİ ALINAMAZ, ORTAM",
322
+ "agree_word": "\"haklısın\"",
323
+ "opener_short": "\"haklısın\", \"you're right\", \"good catch\", \"detaylı bakmadım\", \"I didn't look closely\"",
324
+ "decision_gloss": "DECISION: ",
325
+ "access_gloss": "ACCESS: ",
326
+ "irreversible_gloss": "IRREVERSIBLE: ",
327
+ "env_gloss": "ENV: ",
328
+ "blockers_heading": "Engeller",
329
+ "decision": "KARAR",
330
+ "access": "YETKİ",
331
+ "irreversible": "GERİ ALINAMAZ",
332
+ "env": "ORTAM",
333
+ "done_claim": "yaptım",
334
+ "opener_examples": "\"haklısın\", \"you're right\", \"absolutely right\", \"good catch\", \"iyi yakaladın\", \"detaylı bakmadım\", \"I didn't look closely\", \"I should have checked\"",
335
+ "opener_ban": "never \"haklısın\" / \"you're right\" / \"detaylı bakmadım\" / an apology",
336
+ "residual_lead": "Bu maddeleri şimdi yap veya engel türü ve kanıtla yaz. ",
337
+ "slice_lead": "Durmuş bir dilim var. ",
338
+ "ready_lead": "Hazır adımlar bekliyor. ",
339
+ "ask_lead": "Bu soruyu sorma: kararı ver ya da önerili onay sorusuna çevir. ",
340
+ "approval_heading": "Onay için sorular",
341
+ "recommended": "Öneri",
342
+ "grant_examples": "\"bana sormadan pushla\", \"onay veriyorum\""
343
+ }
344
+ }
@@ -31,6 +31,18 @@ try:
31
31
  except Exception as exc:
32
32
  import_failed(exc)
33
33
 
34
+
35
+ def cross_note(session_id, tool, inp, cwd):
36
+ """The cross-project write notice (hooks/tezgah_gate.py::cross_project_note),
37
+ imported here and not at the top: a gate module without it costs this one
38
+ line, never the evidence row."""
39
+ try:
40
+ from tezgah_gate import cross_project_note
41
+ except ImportError:
42
+ return None
43
+ return cross_project_note(session_id, tool, inp, cwd)
44
+
45
+
34
46
  # The tool-use kinds this hook can see, for the status line's used marks. Claude
35
47
  # reads them from its transcript and ignores this store, but dsh runs this same
36
48
  # file with no transcript of its own - the store is the only channel its Web
@@ -139,13 +151,20 @@ def main():
139
151
  # the Bash result's own stdout/stderr, read on a bounded tail for the
140
152
  # empty-run contract (tezgah_integrity.EMPTY_RUN)
141
153
  empty_run=ran_nothing(result),
142
- agent=agent)
154
+ agent=agent,
155
+ # a background spawn's result names its child (`agentId`), the
156
+ # `agent_id` that child's own calls carry: its slice record keeps it
157
+ # (hooks/tezgah_gate.py::lease_reason)
158
+ child=(result.get("agentId") if isinstance(result, dict)
159
+ and result.get("status") == "async_launched" else None))
143
160
  # the opt-in taste note: the learnings in scope for the first write to this
144
- # file type in the session (hooks/tezgah_taste.write_note), beside the
145
- # provenance line rather than instead of it
161
+ # file type in the session (hooks/tezgah_taste.write_note), and the
162
+ # cross-project write notice (hooks/tezgah_gate.py::cross_project_note),
163
+ # beside the provenance line rather than instead of it
146
164
  if event == "PostToolUse" and not failed:
147
- notice = "\n".join(t for t in (notice, safe(session_id, write_note, session_id,
148
- inp, cwd, tool)) if t)
165
+ notice = "\n".join(t for t in (
166
+ notice, safe(session_id, write_note, session_id, inp, cwd, tool),
167
+ safe(session_id, cross_note, session_id, tool, inp, cwd)) if t)
149
168
  if notice:
150
169
  json.dump({"hookSpecificOutput": {
151
170
  "hookEventName": event,
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python3
2
- """Claude Code PreToolUse hook (matcher Agent|Task|Grep|Bash), inert outside roots.
2
+ """Claude Code PreToolUse hook (matcher Agent|Task|Grep|Bash|...|AskUserQuestion),
3
+ inert outside roots.
3
4
 
4
5
  Claude's envelope around the shared gate (hooks/tezgah_gate.py): refuse the
5
6
  grep-only explorer subagent, and nudge the first code-symbol search of a
@@ -13,15 +14,19 @@ import sys
13
14
  sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
14
15
  from tezgah_guard import import_failed, safe # noqa: E402
15
16
  try:
16
- from tezgah_gate import decision, graph_advice # noqa: E402
17
+ from tezgah_gate import ask_advice, decision, graph_advice, spawn_advice # noqa: E402
17
18
  except Exception as exc:
18
19
  import_failed(exc)
19
20
 
20
21
 
21
22
  def verdict(tool, inp, cwd, session_id, agent):
22
- """(deny reason, graph line): the line only for a call the gate lets through."""
23
+ """(deny reason, advice line): the graph line, the shared-worktree warning
24
+ of a spawn or the ask-policy warning of an AskUserQuestion call, only for a
25
+ call the gate lets through."""
23
26
  reason = decision(tool, inp, cwd, session_id, agent=agent)
24
- return reason, None if reason else graph_advice(tool, inp, cwd, "claude")
27
+ return reason, None if reason else (graph_advice(tool, inp, cwd, "claude")
28
+ or spawn_advice(tool, inp, session_id, cwd)
29
+ or ask_advice(tool, inp, session_id, cwd))
25
30
 
26
31
 
27
32
  def main():
@@ -1,16 +1,23 @@
1
1
  #!/usr/bin/env python3
2
2
  """Claude Code Stop / SubagentStop hook: refuse to end a turn on a false claim.
3
3
 
4
- Blocks (decision: "block") when the final message opens by placating, or claims
4
+ Blocks (decision: "block") when the final message opens by placating, claims
5
5
  done/tested/passing in a session whose newest turn changed code and left a check
6
- failing or unproven by a later pass. An explicit "doğrulanmadı" always clears
7
- it, so honest uncertainty is never punished. With `stop_hook_active` set - the
8
- reply after a block - the reply is judged in record-only mode (an `after_block`
9
- row) and never blocked again, and Claude Code overrides the hook after its own
10
- consecutive-block cap, so this can never trap a session. A subagent's end
11
- (SubagentStop) is judged record-only too: one `subagent_end` row, never a
12
- block (ADR 011). Inert outside a tezgah root or under the `verify-off` kill
13
- switch.
6
+ failing or unproven by a later pass, or ends a turn that did work on a list of
7
+ what is left with an item no blocker accounts for (`residual work`). An explicit
8
+ "doğrulanmadı" clears only a claim whose repair is a check, and only after a
9
+ check that ran and failed since the newest change: the word alone used to clear
10
+ every refusal, so writing it was cheaper than verifying (plan 080). With
11
+ `stop_hook_active` set - the reply after a block - the reply is judged again:
12
+ it is refused once more only for a reason class this turn was not refused for
13
+ yet, at most two refusals per turn (`tezgah_integrity._record_only`, counted
14
+ from the ledger), and otherwise recorded as an `after_block` row. Claude Code
15
+ also overrides the hook after its own consecutive-block cap, so this can never
16
+ trap a session. A subagent's end (SubagentStop) is judged record-only: one
17
+ `subagent_end` row, never a block (ADR 011); it also closes the slice record
18
+ of a background child that ended (`tezgah_task.close_child`), so its lease
19
+ goes with it. Inert outside a tezgah root or under the `verify-off` kill
20
+ switch (the record close only under `slices-off`).
14
21
  """
15
22
  import json
16
23
  import os
@@ -24,10 +31,13 @@ try:
24
31
  except Exception as exc:
25
32
  import_failed(exc)
26
33
 
27
- # How many times one stop chain may be refused: the one-nudge semantics is
28
- # deliberate, and raising it is owner decision 11. Claude says only whether a
29
- # block came before (`stop_hook_active`), so a chain has blocked 0 or 1 times.
30
- STOP_REASKS = 1
34
+
35
+ def close_child(cwd, session_id, agent_id):
36
+ """The background child's record closes when its SubagentStop arrives:
37
+ Claude sends no other end for a `run_in_background` launch."""
38
+ import tezgah_task
39
+ root = tezgah_task.main_repo(cwd)
40
+ return root and tezgah_task.close_child(root, session_id, agent_id)
31
41
 
32
42
 
33
43
  def main():
@@ -39,20 +49,22 @@ def main():
39
49
  return
40
50
  session_id = p.get("session_id")
41
51
  safe(session_id, bind_session, session_id) # the switch latch (tezgah_paths.off)
52
+ cwd = p.get("cwd") or os.getcwd()
53
+ if p.get("hook_event_name") == "SubagentStop" and p.get("agent_id") \
54
+ and root_for(cwd) and not off("slices-off"):
55
+ safe(session_id, close_child, cwd, session_id, p.get("agent_id"))
42
56
  if off("verify-off"):
43
57
  return
44
- cwd = p.get("cwd") or os.getcwd()
45
58
  if not root_for(cwd):
46
59
  return
47
60
  if p.get("hook_event_name") == "SubagentStop":
48
61
  safe(session_id, stop_reason, p.get("last_assistant_message"),
49
62
  session_id, cwd=cwd, subagent=True, agent=p.get("agent_id"))
50
63
  return
51
- blocked = 1 if p.get("stop_hook_active") else 0
52
64
  # a core that cannot answer has refused nothing, so the turn ends: the rule
53
65
  # never traps a session, and that holds for its own failure too
54
66
  reason = safe(session_id, stop_reason, p.get("last_assistant_message"),
55
- session_id, cwd=cwd, record_only=blocked >= STOP_REASKS)
67
+ session_id, cwd=cwd, after_block=bool(p.get("stop_hook_active")))
56
68
  if reason:
57
69
  json.dump({"decision": "block", "reason": reason}, sys.stdout)
58
70
 
@@ -37,7 +37,7 @@ import subprocess
37
37
 
38
38
  import tezgah_models as tm
39
39
  from tezgah_paths import (CONFIG_DIR, HOME, codegraph_bin, host_installed, off,
40
- root_for)
40
+ root_for, say)
41
41
  from tezgah_paths import HOST_DIRS as HOST_HOMES
42
42
 
43
43
  MARKER = "# tezgah: managed by tezgah-agents; do not edit"
@@ -186,6 +186,7 @@ def detect_infra(root):
186
186
  # ------------------------------------------------------------------ roles ----
187
187
 
188
188
  def _reviewer_body(host):
189
+ decision = say()["decision"]
189
190
  return (
190
191
  "You are tezgah-reviewer, an adversarial code reviewer. Review a change,\n"
191
192
  "not the whole repo, with the code graph as below.\n\n"
@@ -221,10 +222,11 @@ def _reviewer_body(host):
221
222
  "provisional. Disclose the order you read the files in.\n\n"
222
223
  "Scope and budget. One review per plan, over its whole diff in the\n"
223
224
  "verification phase; at most two rounds - only a confirmed critical or\n"
224
- "major finding opens round two, a minor or suggestion one is recorded\n"
225
- "fix-later, and after round two what is left is fixed by the session\n"
226
- "and closed with `--resolved`, or recorded fix-later, never a third\n"
227
- "round. A round may be a fan-out of\n"
225
+ "major finding opens round two; a minor or suggestion one is fixed in the\n"
226
+ "session without a new round, or recorded fix-later only when it waits\n"
227
+ "on a user decision (%s); after round two what is left is fixed by\n"
228
+ "the session and closed with `--resolved`, or recorded fix-later only\n"
229
+ "with %s, never a third round. A round may be a fan-out of\n"
228
230
  "reviewers spawned at once, one per dimension (correctness and contract,\n"
229
231
  "security, tests and performance) or per file group: when your brief\n"
230
232
  "names a dimension or files, review only those - a sibling owns the rest.\n"
@@ -237,7 +239,7 @@ def _reviewer_body(host):
237
239
  "specific accusation needs it. The same defect family confirmed in both\n"
238
240
  "rounds is a sign the design needs a pivot, not another patch.\n\n"
239
241
  "%s" % (_graph_howto(host), _blast_radius(host), EMPTY_IS_NOT_PROOF,
240
- _may_use(host)))
242
+ decision, decision, _may_use(host)))
241
243
 
242
244
 
243
245
  def _worker_body(tier):
@@ -419,9 +421,26 @@ def _orch_body(names):
419
421
  "--name <slug> --parent-worktree active --json` when the session runs\n"
420
422
  "inside Orca, else `git worktree add -b <branch> <absolute path>` - and\n"
421
423
  "brief it with absolute paths under that checkout only, never the main\n"
422
- "checkout. Serialize only a real\n"
423
- "dependency, and never wait idle while independent work remains; you\n"
424
- "integrate the branches and run the checks once on the merged tree.\n\n"
424
+ "checkout. Every writing brief names its `Owns:` globs (the files only\n"
425
+ "that slice writes; the gate holds its siblings to them) and declares\n"
426
+ "its checkout on a `Worktree: <abs path>` line, and siblings\n"
427
+ "message each other only on an interface or ownership change - status\n"
428
+ "goes to you. Serialize only a real\n"
429
+ "dependency. Your todo list is the step queue: each open item is ready\n"
430
+ "or blocked on something named (a slice id, %s).\n"
431
+ "After every spawn and every landed slice, dispatch every ready\n"
432
+ "item at once, before any `wait`, and mark each dispatched item blocked\n"
433
+ "on its slice id. Never `wait` while a ready step exists. Once every\n"
434
+ "open item is blocked on a running slice, `wait` or end the turn - the\n"
435
+ "host wakes you on the result. You integrate the branches in the order\n"
436
+ "`tezgah-task slice merge-plan` prints, and own CHANGELOG.md, MANIFEST\n"
437
+ "and the citation baseline. The per-turn\n"
438
+ "checks of what changed still run in the turn, in the background; only\n"
439
+ "the heavy tier (full suite, neuter, e2e) is joined at merge.\n"
440
+ "A slice commits `wip: <step>` after each step. A stopped slice is\n"
441
+ "resumed (`tezgah-task slice resume <id>`) or re-dispatched, never\n"
442
+ "silently absorbed inline; run `tezgah-task slice reconcile --prune`\n"
443
+ "before the turn that merged slices ends.\n\n"
425
444
  "Route reviews to tezgah-reviewer, with the changed files and symbols in\n"
426
445
  "the brief: where it has no shell it cannot run `git diff` itself. Checks\n"
427
446
  "go to tezgah-tester, docs and citations to tezgah-docs, a security review\n"
@@ -433,7 +452,7 @@ def _orch_body(names):
433
452
  "tezgah-frontier); an ESCALATE answer is restarted on tezgah-frontier with\n"
434
453
  "the same brief. Never delegate a task a specialist is not\n"
435
454
  "listed for, and never let a subagent spawn its own subagents. Verify each\n"
436
- "returned claim against the code before acting." % listed)
455
+ "returned claim against the code before acting." % (listed, say()["blocker_tokens"]))
437
456
 
438
457
 
439
458
  # ---------------------------------------------------------------- renderers --
@@ -4,7 +4,8 @@ Four rules are counted per file over docs/*.md and CHANGELOG.md: sentences over
4
4
  25 words, semicolons, a short list of words with a plainer replacement, and
5
5
  passive voice. Only English prose written for people is read: fenced code,
6
6
  code spans (including one broken across lines), link targets, HTML comments,
7
- tables, headings and any line holding a Turkish letter are blanked first, with
7
+ tables, headings and any line holding another language's marker letter (a
8
+ language pack's `markers.letters`, hooks/lang/) are blanked first, with
8
9
  their newlines kept so a hit still names its line.
9
10
 
10
11
  The counts are a ratchet, not a style gate: `docs/clarity-baseline.json` holds
@@ -19,6 +20,8 @@ import json
19
20
  import os
20
21
  import re
21
22
 
23
+ from tezgah_paths import packs
24
+
22
25
  RULES = ("long_sentences", "semicolons", "replace_words", "passive")
23
26
  LONG = 25
24
27
  REPLACE = ("commence", "initiate", "utilize", "prior to", "in order to", "ensure",
@@ -33,7 +36,8 @@ FENCE = re.compile(r"^\s*(```|~~~)")
33
36
  SPAN = re.compile(r"(?<!`)(`+)(?!`)(.+?)(?<!`)\1(?!`)", re.S)
34
37
  COMMENT = re.compile(r"<!--.*?-->", re.S)
35
38
  LINK_TARGET = re.compile(r"\]\([^)]*\)|\]\[[^\]]*\]|<https?://[^>]*>|https?://\S+")
36
- TURKISH = re.compile(r"[ğĞışŞçÇöÖüÜİ]")
39
+ OTHER_LANGUAGE = re.compile("[%s]" % "".join(
40
+ c for p in packs().values() for c in p["markers"]["letters"]))
37
41
  SKIP_LINE = re.compile(r"^\s*(?:#|\||\[[^\]]+\]:\s)")
38
42
  ITEM = re.compile(r"^\s*(?:[-*+]|\d+[.)])\s+")
39
43
  BASELINE = os.path.join("docs", "clarity-baseline.json")
@@ -58,7 +62,7 @@ def prose(text):
58
62
  out.append(SPAN.sub(lambda m: _blank(m, " CODE "), para))
59
63
  text = LINK_TARGET.sub(lambda m: "]" if m.group(0)[0] == "]" else "",
60
64
  COMMENT.sub(_blank, "".join(out)))
61
- return "\n".join("" if SKIP_LINE.match(line) or TURKISH.search(line) else line
65
+ return "\n".join("" if SKIP_LINE.match(line) or OTHER_LANGUAGE.search(line) else line
62
66
  for line in text.split("\n"))
63
67
 
64
68