Po 3 takich samych błędach narzędzia z rzędu zatrzymuje Claude'a i pyta, co dalej

Tu leży wszystko, co rozdaję na kanale. Za darmo, bez zapisywania się na cokolwiek.
Jak pobrać: kliknij zielony przycisk Code u góry, potem Download ZIP. Rozpakuj na pulpit. Nie musisz wiedzieć, co to GitHub — wystarczy ten jeden przycisk.
Skill to instrukcja, którą AI wykona. W czymkolwiek ściągniętym z internetu może być napisane wszystko. Sprawdzaj każdą paczkę, zanim ją wrzucisz. Moją też.
Paczka leży jeszcze w zwykłym folderze na pulpicie, więc otwórz nową rozmowę z AI w tym folderze i wklej:
Zanim tego użyję: przeczytaj te pliki jak zwykły tekst i powiedz mi po ludzku,
co ta instrukcja każe robić. Czy każe coś kasować, wysyłać gdzieś dane,
uruchamiać komendy albo grzebać poza swoim folderem?
Zasada kciuka: jeśli w instrukcji jest „wyślij", „skasuj" albo „uruchom" coś, czego nie rozumiesz — nie instalujesz. Nie musisz rozumieć wszystkiego. Wystarczy, że wiesz, kiedy powiedzieć „nie".
To nie jest kontrola pancerna, ale wyłapuje zdecydowaną większość śmieci. Różnica jak między wzięciem cukierka od obcego a przeczytaniem składu.
| Folder | Co to robi | Odcinek |
|---|---|---|
ghost/ | AI pisze maile i wiadomości twoim stylem, a nie jak robot | „Nauczyłem AI pisać jak ja" |
handoff/ | Kończysz rozmowę tak, żeby nowa wiedziała, na czym stanęliście — mniej zużytego limitu | „Znowu masz limit" |
krotko/ | Jedno słowo i z długiej odpowiedzi AI zostaje kilka zdań po ludzku | „AI gada za dużo" |
mody-limit/ | Trzech pomocników w Claude Code: pasek zużycia w kolorach, przycinanie gadatliwych wyników, stop dla AI kręcącego się w kółko | (odcinek w przygotowaniu) |
Każdy folder ma własny README.md z instrukcją krok po kroku.
Napisz w komentarzu pod odcinkiem — czytam wszystkie i z powtarzających się pytań robię następne filmy.
hooks/register.ts 109 lines1import type { EngineInterface, Register, ToolCallResult } from 'claude-code'
2
3// Tyle takich samych błędów z rzędu i Strażnik pyta użytkownika.
4const LIMIT = 3
5
6const STOP = 'Stop, niech wyjaśni'
7const AGAIN = 'Niech próbuje dalej'
8
9// Błąd → ile razy z rzędu. Klucz: kto (główna rozmowa / subagent) + narzędzie + treść błędu.
10let failures = new Map<string, number>()
11// Błędy, przy których użytkownik kazał próbować dalej — do jego następnej wiadomości.
12let allowed = new Set<string>()
13// Błędy, przy których użytkownik kazał przestać — kolejna taka próba nie rusza.
14let stopped = new Set<string>()
15
16const reset = () => {
17 failures = new Map()
18 allowed = new Set()
19 stopped = new Set()
20}
21
22// Ten sam błąd mimo innych liczb (czas, numer linii, id) liczy się jako ten sam.
23export const signature = (who: string, tool: string, error: string) =>
24 `${who}|${tool}|${error.toLowerCase().replace(/\d+/g, '#').replace(/\s+/g, ' ').trim().slice(0, 300)}`
25
26export const register: Register = on => {
27 on('session.start', async ($, e, next) => {
28 reset()
29 return next(e)
30 })
31
32 // Nowa wiadomość od użytkownika: zaczynamy liczyć od zera.
33 on('prompt.submit', async ($, e, next) => {
34 reset()
35 return next(e)
36 })
37
38 on('tool.call', async ($, e, next) => {
39 if (e.tool === 'AskUserQuestion') {
40 return next(e)
41 }
42
43 const who = e.agentId ?? 'main'
44 const ran = await next(e)
45 if (ran.deny !== undefined) {
46 return ran
47 }
48
49 // Udane wywołanie tego narzędzia przerywa serię jego błędów.
50 if (ran.isError !== true) {
51 for (const key of failures.keys()) {
52 if (key.startsWith(`${who}|${e.tool}|`)) failures.delete(key)
53 }
54 return ran
55 }
56
57 const key = signature(who, e.tool, ran.text ?? String(ran.result ?? ''))
58 if (allowed.has(key)) {
59 return ran
60 }
61 if (stopped.has(key)) {
62 return withNote(ran, 'Użytkownik już kazał przestać przy tym błędzie. Nie próbuj ponownie — napisz mu, co się dzieje, i czekaj na odpowiedź.')
63 }
64
65 const count = (failures.get(key) ?? 0) + 1
66 failures.set(key, count)
67 if (count < LIMIT) {
68 return ran
69 }
70
71 failures.delete(key)
72 return ask($, e.tool, who, key, ran)
73 })
74}
75
76async function ask($: EngineInterface, tool: string, who: string, key: string, ran: ToolCallResult): Promise<ToolCallResult> {
77 const error = (ran.text ?? '').replace(/\s+/g, ' ').trim().slice(0, 160)
78 const agent = who === 'main' ? 'Claude' : 'Subagent Claude’a'
79 const question = `${agent} ${LIMIT} razy z rzędu dostał ten sam błąd w ${tool}: „${error}”. Co robimy?`
80
81 let answer: string
82 try {
83 answer = await $.ui.ask(question, { options: [STOP, AGAIN], header: 'Pętla' })
84 } catch (err) {
85 // Nie było kogo zapytać albo okno zamknięto: bezpieczniej stanąć.
86 $.ui.log(`straznik-petli: okienko pytania nie wyszło: ${String(err).slice(0, 300)}`)
87 stopped.add(key)
88 $.ui.toast(`Strażnik pętli zatrzymał Claude'a: ten sam błąd ${LIMIT} razy w ${tool}.`, { timeoutMs: 15000 })
89 return withNote(ran, `Strażnik pętli: ten sam błąd padł ${LIMIT} razy z rzędu (nie dało się zapytać użytkownika). Nie próbuj ponownie. Napisz mu krótko, prostym językiem: co chciałeś zrobić, co próbowałeś i co Twoim zdaniem jest przyczyną — potem zapytaj, co dalej.`)
90 }
91
92 if (answer === AGAIN) {
93 allowed.add(key)
94 return withNote(ran, `Strażnik pętli: ten sam błąd padł ${LIMIT} razy, ale użytkownik pozwolił próbować dalej. Zmień podejście, zamiast powtarzać to samo.`)
95 }
96 if (answer === STOP) {
97 stopped.add(key)
98 return withNote(ran, `Strażnik pętli: ten sam błąd padł ${LIMIT} razy z rzędu i użytkownik kazał przestać. Nie próbuj ponownie. Napisz mu krótko, prostym językiem: co chciałeś zrobić, co próbowałeś i co Twoim zdaniem jest przyczyną — potem zapytaj, co dalej.`)
99 }
100
101 // Użytkownik wpisał własną odpowiedź w „Other”.
102 allowed.add(key)
103 return withNote(ran, `Strażnik pętli: ten sam błąd padł ${LIMIT} razy z rzędu. Użytkownik odpowiedział: „${answer}”. Postępuj według tego.`)
104}
105
106// Notka trafia do Claude'a zaraz po wyniku narzędzia (użytkownik jej nie widzi).
107const withNote = (ran: ToolCallResult, note: string): ToolCallResult =>
108 ran.deny !== undefined ? ran : { ...ran, context: [...(ran.context ?? []), note] }
109