Przejdź do głównej zawartości

Skrypty z Claude Code: uruchomienia headless, potoki, cron i hooki git

Skryptowanie Claude Code to uruchamianie claude -p (tryb print) ze skryptu powłoki, hooka git, zadania cron lub kroku CI zamiast sesji interaktywnej. Taki przebieg startuje w trybie uprawnień Manual i nikt nie zatwierdza pytań, więc działa tylko wtedy, gdy skrypt nadaje dokładne uprawnienia, ogranicza tury i koszt oraz sprawdza zwrócony wynik JSON.

Masz prompt, który działa: wrzucasz diff przez potok, prosisz o wpis do changeloga i dopisujesz go do CHANGELOG.md. Przed każdym wydaniem odpalasz go ręcznie i za każdym razem przepisujesz z pamięci. Potem przenosisz go do crona i przez tydzień co noc „kończy się sukcesem”, nie zapisując niczego, bo każda edycja pliku została odrzucona, a skrypt sprawdzał tylko, czy proces się zakończył. Ta strona jest dla developera albo tech leada, który chce, żeby takie przebiegi były powtarzalne i głośno zgłaszały błędy. Zakłada, że Claude Code jest zainstalowany i zalogowany; przegląd sekcji Automatyzacja pokazuje, gdzie skrypty stoją obok hooków, routines i Agent SDK.

  • Skrypt opakowujący, który uruchamia jedno zadanie bez nadzoru, ponawia tylko awarie przejściowe i kończy się kodem niezerowym, jeśli przebieg naprawdę się nie udał.
  • Przepisy na uprawnienia dla skryptów, od raportów tylko do odczytu po edycje w jednym katalogu, oraz pułapkę w ustawieniach projektu, która po cichu wyłącza twoje reguły allow.
  • Bramkę pre-commit, która zwraca werdykt zwalidowany schematem zamiast tekstu do grepowania.
  • Wzorzec zadania cron z uwierzytelnianiem, jednorazową gałęzią i raportem, który scala człowiek.
  • Prompty do skopiowania: skill wydania, masowa migracja i zadanie utrzymaniowe.

Wybierz mechanizm, zanim napiszesz prompt. Większość błędów z sekcji o awariach na końcu strony bierze się z uruchomienia zadania w niewłaściwym miejscu.

Chcesz…UżyjDlaczego
Powtarzać wieloetapowe zadanie, patrząc na nieSkill (/release) w sesji interaktywnejMożesz odpowiadać na pytania i zatwierdzać ryzykowne kroki.
Uruchomić jedno zadanie ze skryptu, Makefile’a albo hooka gitclaude -pWejście na stdin, wynik na stdout, kod wyjścia dla wywołującego. Temat tej strony.
Uruchamiać zadanie według harmonogramu przy zamkniętym laptopieRoutinesSesje w chmurze Anthropic; research preview, minimalny odstęp to godzina.
Uruchamiać zadanie według harmonogramu na własnej maszyniecron + claude -pTwoja sieć, twoje poświadczenia, dowolny odstęp.
Przeglądać PR-y albo reagować na zgłoszenia w GitHubieanthropics/claude-code-action@v1Działa na zdarzeniach i harmonogramach GitHuba, komentuje PR.
Reagować na każdą edycję, którą Claude robi w sesjiHookiDeterministyczne polecenia powłoki na zdarzeniach cyklu życia, bez promptu.
Zbudować długo działający program wokół pętli agentaClaude Agent SDKSesje, callbacki i uprawnienia z Pythona albo TypeScriptu.

Pięć różnic decyduje o tym, czy skrypt zadziała. Wszystkie sprawdziliśmy 2026-09-26 na Claude Code 2.1.283 i w dokumentacji trybu headless.

  1. Startuje w trybie Manual na każdym planie. Na kanale latest tryb auto jest domyślny w sesjach interaktywnych, ale nie w -p. Wszystko, co wymagałoby zatwierdzenia, zostaje odrzucone, bo nikt nie odpowie, a przebieg idzie dalej bez tego.
  2. Pomija okno zaufania do workspace’u. Hooki projektu, jego blok env i wszystkie serwery z .mcp.json nadal się ładują i działają. Reguły permissions.allow z .claude/settings.json projektu nie obowiązują w folderze, któremu nigdy nie zaufałeś interaktywnie; Claude Code wypisuje wtedy na stderr ostrzeżenie this workspace has not been trusted. Świeży checkout w CI albo w cronie to właśnie taki folder, więc podawaj uprawnienia w linii poleceń.
  3. Kod wyjścia ma znaczenie. Wynosi 0 przy sukcesie i jest niezerowy, gdy przebieg się nie powiedzie, także po osiągnięciu --max-turns. Błąd wewnątrz przebiegu, na przykład brak uwierzytelnienia, trafia jako wynik na stdout. SIGTERM kończy proces kodem 143 i nie zapisuje wyniku.
  4. Stdin ma limit 10 MB. Powyżej Claude Code kończy się błędem. Większe dane zapisz do pliku i podaj ścieżkę w prompcie.
  5. --bare pomija lokalną konfigurację. Pomija hooki, pluginy, pamięć automatyczną oraz automatyczne wykrywanie skilli, serwerów MCP i CLAUDE.md, a uwierzytelnia się wyłącznie przez ANTHROPIC_API_KEY (albo apiKeyHelper przekazany w --settings), nigdy przez login do subskrypcji. claude --help (2.1.283) podaje też, że skille „still resolve via /skill-name”, więc skill wprost wymieniony w prompcie może się mimo to rozwinąć. Używaj --bare, gdy zadanie ma działać identycznie na każdej maszynie, a zadanie oparte na skillu uruchom raz z --bare, zanim zaczniesz polegać na którymkolwiek z tych zachowań; pomiń tę flagę, gdy zadanie korzysta z CLAUDE.md. Dokumentacja trybu headless zaleca --bare dla skryptów i zapowiada, że w przyszłym wydaniu stanie się on domyślny dla -p, więc zadanie, które potrzebuje CLAUDE.md, powinno wczytać go jawnie (na przykład przez --append-system-prompt-file CLAUDE.md), zamiast polegać na automatycznym wykrywaniu.

Formaty wyjścia:

--output-formatDostajeszZastosowanie
text (domyślny)Tylko końcową odpowiedźTekst dla człowieka albo plik, który commitujesz
jsonJeden obiekt wyniku: subtype, is_error, result, total_cost_usd, permission_denials, session_idKażdy skrypt, który rozgałęzia się na wyniku
stream-jsonZdarzenia w formacie NDJSON na bieżącoPostęp na żywo i długie zadania

Dodaj --json-schema do --output-format json, a zwalidowany obiekt trafi do pola structured_output. To różnica między parsowaniem prozy grepem a odczytem pola.

Nadaj skryptowi dokładnie te uprawnienia, których potrzebuje

Dział zatytułowany „Nadaj skryptowi dokładnie te uprawnienia, których potrzebuje”

Zdecyduj, co zadanie może robić, zanim się uruchomi, i zapisz to w linii poleceń, żeby uprawnienia podróżowały razem ze skryptem.

ZadanieFlagi
Raport albo przegląd tylko do odczytu--permission-mode dontAsk (odczyty w katalogu roboczym i polecenia tylko do odczytu nadal działają)
Raport, który uruchamia konkretne polecenia--permission-mode dontAsk --allowedTools "Bash(npm audit *),Bash(npm outdated *)"
Edycje ograniczone do jednego katalogu--permission-mode dontAsk --allowedTools "Edit(./src/api/**),Bash(npm test *)"
Szerokie zmiany, przy których każdą akcję ma ocenić klasyfikator--permission-mode auto --permission-prompts none
Wszystko wolno--dangerously-skip-permissions, tylko w jednorazowym sandboksie bez sieci i bez sekretów

W skryptach liczą się trzy szczegóły reguł. Końcowe * w Bash(npm test *) oznacza dopasowanie prefiksu, a spacja przed * sprawia, że reguła nie pasuje do npm test-e2e. Reguły ścieżek są sprawdzane tylko dla Edit(...) i Read(...): reguła Write(reports/**) zostanie przyjęta i nigdy nie będzie użyta, więc pisz Edit(./reports/**). A dontAsk odrzuca wszystko, czego nie wymieniłeś, i właśnie tego chcesz, gdy nikt nie patrzy.

Każde zadanie bez nadzoru z tej strony przechodzi przez jeden wrapper. Ponawia próbę tylko wtedy, gdy nie ma żadnego wyniku (awaria sieci albo procesu), a nigdy wtedy, gdy Claude zadziałał i zatrzymał się z konkretnego powodu, bo druga próba zadania, które wyczerpało limit tur, tylko podwaja rachunek.

#!/usr/bin/env bash
# scripts/claude-job.sh — uruchamia jedno zadanie Claude Code bez nadzoru; kod niezerowy, jeśli się nie udało.
# Użycie: scripts/claude-job.sh "PROMPT" [dodatkowe flagi claude...]
set -euo pipefail
PROMPT="$1"; shift
RUN_DIR="${RUN_DIR:-.claude-runs}"
mkdir -p "$RUN_DIR"
OUT="$RUN_DIR/$(date +%Y%m%dT%H%M%S).json"
for attempt in 1 2 3; do
claude -p "$PROMPT" \
--output-format json \
--permission-mode dontAsk \
--max-turns 25 \
--max-budget-usd 3.00 \
"$@" > "$OUT" 2>> "$RUN_DIR/stderr.log" && break
# Obiekt wyniku oznacza, że Claude zadziałał i zatrzymał się celowo: ponowienie nie pomoże.
jq -e '.type == "result"' "$OUT" > /dev/null 2>&1 && break
[ "$attempt" -lt 3 ] || break # bez czekania po ostatniej próbie
echo "attempt $attempt produced no result; retrying in $((attempt * 30))s" >&2
sleep $((attempt * 30))
done
subtype=$(jq -r '.subtype // "missing"' "$OUT" 2> /dev/null || echo missing)
is_error=$(jq -r '.is_error' "$OUT" 2> /dev/null || echo null)
cost=$(jq -r '.total_cost_usd // 0' "$OUT" 2> /dev/null || echo 0)
denied=$(jq -r '(.permission_denials // []) | length' "$OUT" 2> /dev/null || echo 0)
echo "subtype=$subtype is_error=$is_error cost_usd=$cost denials=$denied" >&2
if [ "$denied" != "0" ]; then
echo "denied tool calls (grant them or change the prompt):" >&2
jq -c '.permission_denials[]' "$OUT" >&2
[ "${ALLOW_DENIALS:-0}" = 1 ] || exit 1 # odrzucone wywołanie kończy zadanie błędem, chyba że wywołujący wyrazi zgodę
fi
[ "$subtype" = "success" ] && [ "$is_error" = "false" ] || exit 1
jq -r '.result' "$OUT"

Wywołujący dodaje własne uprawnienia po prompcie, na przykład scripts/claude-job.sh "Summarize open TODOs" --allowedTools "Bash(git log *)". Przebieg z choćby jednym odrzuconym wywołaniem narzędzia kończy się kodem 1, nawet gdy subtype to success, bo to właśnie zadanie, które „kończy się sukcesem”, niczego nie zapisując. Zadanie, które spodziewa się odmów, na przykład raport mogący sięgnąć po polecenie, którego celowo nie nadałeś, musi to jawnie zadeklarować: ALLOW_DENIALS=1 scripts/claude-job.sh …. Flaga --max-turns działa, ale nie ma jej w claude --help (sprawdzone na 2.1.283; przebieg po limicie kończy się kodem 1 i subtype równym error_max_turns); udokumentowanym limitem jest --max-budget-usd. Pliki JSON w .claude-runs/ to twój ślad audytowy: dodaj katalog do .gitignore i trzymaj pliki tak długo, jak logi CI.

Zostaw model domyślny dla Claude Code. W raporcie o dużym wolumenie, w którym liczy się koszt, dodaj --model z tańszym aliasem, takim jak sonnet, dopiero wtedy, gdy twoje własne testy pokażą, że wynik nadal się broni; aktualne opcje i ceny znajdziesz w przeglądzie modeli.

Potok to najtańsza integracja: dane przychodzą na stdin, więc Claude nie potrzebuje uprawnień do Bash, żeby je pobrać.

Okno terminala
# Wyjaśnij nieudany build, nie pozwalając Claude niczego dotknąć
npm run build 2>&1 | claude -p "Explain the root cause of each distinct error, most fundamental first. Name the file and line. Do not propose fixes for errors caused by an earlier one."
# Linter literówek jako skrypt npm (z dokumentacji trybu headless)
git diff main | claude -p "you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next. return nothing else."
# Wpis do changeloga z commitów od ostatniego taga
git log --oneline "$(git describe --tags --abbrev=0)..HEAD" \
| claude -p "Write a Keep a Changelog entry for version 2.4.0 dated $(date +%F). Group under Added, Changed, Fixed, Removed. One line per user-visible change, past tense. Drop chore and CI commits." \
> /tmp/changelog-entry.md

Przekieruj wynik do pliku i przejrzyj go, zanim trafi dalej; potok zapisujący prosto do CHANGELOG.md zamienia jeden zły przebieg w zły commit.

Zamień powtarzany prompt w skill, który wywołają twoje skrypty

Dział zatytułowany „Zamień powtarzany prompt w skill, który wywołają twoje skrypty”

Gdy prompt ma więcej niż trzy kroki, przestań go wklejać. Polecenia niestandardowe są teraz skillami: plik .claude/skills/release/SKILL.md i starszy .claude/commands/release.md tworzą to samo /release, a istniejące pliki poleceń nadal działają. Format opisuje przewodnik po poleceniach niestandardowych; przy skryptach liczą się dwie rzeczy: disable-model-invocation: true, żeby Claude nigdy sam z siebie nie zaczął wydania, oraz $ARGUMENTS, które dostaje wszystko, co stoi po nazwie polecenia.

Przebieg -p rozwija skill wymieniony w prompcie, więc ten sam plik obsługuje ciebie w sesji i twoje skrypty bez nadzoru:

Okno terminala
scripts/claude-job.sh "/release minor" \
--allowedTools "Edit(./package.json),Edit(./CHANGELOG.md),Bash(npm test *),Bash(git add *),Bash(git commit *),Bash(git tag *)"

Lista celowo pomija git push. Skrypt taguje lokalnie; wypycha człowiek albo CI, po przeczytaniu diffu taga.

Hook git pre-commit uruchamia się przed każdym commitem, w twoim terminalu, niezależnie od tego, czy kod napisał Claude. To coś innego niż hook Claude Code, który działa na wywołaniach narzędzi Claude wewnątrz sesji. Hooka git używaj do ostatniej kontroli zestagowanego diffu; hooków Claude Code do formatowania i blokowania w trakcie sesji.

Ten hook prosi o werdykt zgodny ze schematem JSON, więc skrypt czyta pole, zamiast szukać BLOCK: w prozie, która może brzmieć „nie znaleziono problemów BLOCK:”.

#!/usr/bin/env bash
# .git/hooks/pre-commit — blokuje commit przy krytycznym problemie w zestagowanym diffie
set -euo pipefail
diff=$(git diff --cached --no-color)
[ -z "$diff" ] && exit 0
gitleaks git --staged # najpierw deterministyczny skan sekretów; przy wycieku kod 1 blokuje commit
schema='{"type":"object","properties":{"verdict":{"type":"string","enum":["pass","block"]},"findings":{"type":"array","items":{"type":"string"}}},"required":["verdict","findings"]}'
if ! out=$(printf '%s' "$diff" | claude -p \
"Review this staged diff for critical problems only: credentials or API keys in the code, SQL built by string concatenation, a removed authorization check, an error swallowed in auth or payment code. Ignore style and naming. Return verdict block only for a problem you can name by file and line; put each one in findings as 'file:line - problem'." \
--output-format json --json-schema "$schema" \
--permission-mode dontAsk --max-turns 3 --max-budget-usd 0.50); then
echo "pre-commit: Claude review did not complete; commit allowed. Re-run before you push." >&2
exit 0
fi
if [ "$(jq -r '.structured_output.verdict // "missing"' <<< "$out")" = "block" ]; then
echo "pre-commit: blocked by Claude review" >&2
jq -r '.structured_output.findings[]' <<< "$out" >&2
echo "Fix the findings, or bypass once with: git commit --no-verify" >&2
exit 1
fi

Zapisz go jako .git/hooks/pre-commit i nadaj prawo wykonywania: chmod +x .git/hooks/pre-commit. Git po cichu pomija hook bez tego prawa, więc skopiowany plik bez niego to bramka, która nigdy się nie uruchamia.

W skrypt wbudowane są dwie decyzje projektowe. Hook przepuszcza commit, gdy Claude nie może się uruchomić (brak sieci, limit zapytań), bo bramka blokująca każdy commit przy błędzie sieci zostanie usunięta w ciągu dnia; zabezpieczeniem jest przegląd w CI. A model to druga linia obrony przed sekretami, nie pierwsza: przed wywołaniem Claude hook uruchamia Gitleaks (open source, około 29,5 tys. gwiazdek na GitHubie we wrześniu 2026), bo dopasowanie wzorców łapie klucz w znanym formacie za każdym razem, a model tylko w większości przypadków. Zainstaluj go przez brew install gitleaks (README podaje też obrazy Dockera i budowanie ze źródeł); gitleaks git --staged skanuje tylko to, co zaraz trafi do commita. Przed wersją 8.19.0 ten sam skan wywoływało się jako gitleaks protect --staged, co nadal działa, ale nie jest widoczne w --help.

Pilnuj, żeby hook był szybki. Kontrola pre-commit trwająca minutę uczy ludzi wpisywać --no-verify. Jeśli twoje diffy są duże, przenieś ją do pre-push.

Używaj crona, gdy zadanie potrzebuje twojej sieci, twoich poświadczeń albo odstępu krótszego niż godzina; używaj routines, gdy ma działać przy zamkniętym laptopie. Zadanie cron, które edytuje kod, trzyma się czterech zasad: własny checkout, jednorazowa gałąź, flagi z minimalnymi uprawnieniami i raport, który czyta człowiek.

/opt/jobs/dep-audit.sh
#!/usr/bin/env bash
# crontab: 7 6 * * 1 /opt/jobs/dep-audit.sh >> /var/log/dep-audit.log 2>&1
set -euo pipefail
export PATH="$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin" # PATH crona nie zawiera natywnej instalacji
source "$HOME/.config/claude-cron.env" # eksportuje CLAUDE_CODE_OAUTH_TOKEN
cd /srv/checkouts/billing-api # checkout, w którym nie pracuje żaden człowiek
git fetch -q origin && git checkout -q -B chore/dep-audit origin/main
/opt/jobs/claude-job.sh \
"Run npm audit --json and npm outdated --json. For each high or critical advisory, grep our src/ for imports of the affected module and mark it reachable or not, naming the importing file. Write reports/dep-audit.md with one table: package, severity, reachable, fixed version, breaking changes in that version. Do not edit package.json or the lockfile." \
--allowedTools "Bash(npm audit *),Bash(npm outdated *),Edit(./reports/**)" \
> /dev/null || { echo "dep-audit failed $(date -Is)" >&2; exit 1; }
git add reports/dep-audit.md
git commit -q -m "chore: weekly dependency audit $(date +%F)" || exit 0 # nic się nie zmieniło
git push -q -f origin chore/dep-audit
gh pr create --fill --head chore/dep-audit 2> /dev/null || true # w kolejnych tygodniach PR już istnieje

Najpierw psuje się uwierzytelnianie. Cron nie ma przeglądarki ani sesji w pęku kluczy, więc wygeneruj roczny token poleceniem claude setup-token i eksportuj go jako CLAUDE_CODE_OAUTH_TOKEN z pliku, który może czytać tylko użytkownik zadania, albo użyj ANTHROPIC_API_KEY, jeśli zadanie ma być rozliczane przez API. Ostatnia linia za pierwszym razem otwiera pull request; w kolejnych tygodniach gh pr create zwraca błąd, bo PR jest już otwarty, a force-push go zaktualizował. Minuta to 7, a nie 0: zadania zaplanowane na pełną godzinę tłoczą się ze wszystkimi innymi.

Przekaż komunikat o błędzie do systemu alertów, który powiadamia zespół. Zadanie z harmonogramu, którego błędy lądują tylko w pliku logu, to zadanie, o którego zatrzymaniu nikt nie wie.

Masowe zmiany uruchamiaj w pętli, nie jednym wielkim promptem

Dział zatytułowany „Masowe zmiany uruchamiaj w pętli, nie jednym wielkim promptem”

Jeden prompt „zmigruj każdy plik” daje jeden ogromny diff i żadnej możliwości ustalenia, który plik zepsuł build. Pętla w powłoce daje każdemu plikowi osobny przebieg, osobną bramkę testów i osobny commit:

Okno terminala
for f in $(git grep -l "from 'moment'" -- ':(glob)src/**/*.ts'); do
scripts/claude-job.sh "Migrate $f from moment to date-fns. Convert format tokens (YYYY-MM-DD becomes yyyy-MM-dd). Change only this file." \
--allowedTools "Edit(./$f)" > /dev/null \
&& [ "$(git diff --name-only)" = "$f" ] \
&& npx vitest related "$f" --run \
&& git add -- "$f" && git commit -qm "refactor: $f moment -> date-fns" \
|| { echo "FAILED: $f" >> migration-failures.txt; git checkout -- . && git clean -fdq src/; }
done

Uprawnienie do edycji obejmuje tylko bieżący plik, a sprawdzenie git diff --name-only oblewa iterację, jeśli zmienił się jakikolwiek inny śledzony plik, więc „zmień tylko ten plik” jest egzekwowane, a nie tylko zapisane w prompcie. Testy uruchamia pętla, już po zakończeniu Claude, więc przebieg, który je pominie albo przekłamie ich wynik, nie wyprodukuje commita. Prefiks :(glob) sprawia, że ** pasuje też do plików leżących bezpośrednio w src/, a git clean usuwa nowe pliki pozostawione przez nieudany przebieg.

Przy zmianach obejmujących dziesiątki niezależnych jednostek w jednej sesji wbudowany skill /batch dzieli pracę na 5 do 30 jednostek, każdą we własnym worktree; zobacz operacje wsadowe. Pętla powyżej sprawdza się wtedy, gdy chcesz jednego commita na plik i listy plików, które się nie udały.

Nikt nie czyta każdej linii diffu z nocnego zadania i nikt nie powinien musieć. Zamiast tego sprawdzaj dowody, w tej kolejności:

  1. Przebieg się udał. Kod wyjścia wrappera, subtype równe success, is_error równe false i pusta lista permission_denials. Przebieg z odmowami mógł „udać się” w mniejszym zadaniu niż to, o które prosiłeś.
  2. Kontrole uruchomił skrypt, nie model. Zadanie kończy się poleceniem npm test albo npx tsc --noEmit, które wykonuje twój skrypt po zakończeniu Claude. Podsumowanie modelu „wszystkie testy przechodzą” nie jest wynikiem testów.
  3. Zmiana nie wyszła poza granice. git diff --stat origin/main...HEAD pokazuje tylko ścieżki dozwolone na liście uprawnień, a liczba plików mieści się w oczekiwanym zakresie. Uznaj zadanie za nieudane (kod niezerowy), jeśli zmienił się lockfile, choć prompt tego zabraniał.
  4. Wynik strukturalny jest zwalidowany. Gdy skrypt korzysta z odpowiedzi Claude, czyta structured_output wygenerowane z --json-schema, nigdy wolny tekst.
  5. Drugi agent przejrzał diff. Przy zmianach w kodzie uruchom na gałęzi /code-review (albo claude ultrareview z powłoki, żeby dostać wieloagentowy przegląd w chmurze; po 3 darmowych przebiegach na Pro i Max każdy kolejny jest płatny, a organizacje z Zero Data Retention nie mają do niego dostępu, podobnie jak użytkownicy Amazon Bedrock, Google Cloud i Microsoft Foundry), zanim spojrzy człowiek.
  6. Koszt jest logowany. total_cost_usd z każdego przebiegu trafia do logu; zadanie, którego koszt podwaja się z tygodnia na tydzień, robi coś nowego.

Człowiek zatwierdza zmianę, scalając PR. Zadania z harmonogramu wypychają gałęzie i otwierają pull requesty; nie wypychają na main. Pełny pakiet, który powinien dostać recenzent, opisuje pakiet dowodów (evidence bundle).

Zadanie „kończy się sukcesem” i niczego nie zmienia. Każdy zapis został odrzucony: -p startuje w trybie Manual, a reguły permissions.allow projektu nie działają w niezaufanym checkoucie. Naprawa: wypisz permission_denials z wyniku JSON i dodaj dokładne reguły przez --allowedTools w linii poleceń.

Zadanie zatrzymuje się z error_max_turns albo error_max_budget_usd. Limit zadziałał zgodnie z przeznaczeniem. Nie ponawiaj tego samego promptu; zawęź zadanie (jeden katalog, jeden pakiet) albo raz podnieś limit i sprawdź num_turns w wyniku, żeby zobaczyć, ile tur było potrzebne.

Zadanie cron działa ręcznie, a o 06:07 pada. Środowisko crona ma minimalny PATH i żadnej sesji logowania. Naprawa: ustaw PATH jawnie w skrypcie, eksportuj CLAUDE_CODE_OAUTH_TOKEN z claude setup-token i testuj przez env -i HOME="$HOME" /bin/bash /opt/jobs/dep-audit.sh, co odtwarza gołe środowisko crona.

Sklonowane repozytorium uruchamia własne hooki i serwery MCP. W -p okno zaufania się nie pojawia, więc hooki z ustawień repozytorium działają, a serwery z jego .mcp.json się łączą. Naprawa: dla kodu, którego nie napisałeś, uruchamiaj z --bare --setting-sources "" --strict-mcp-config. Tryb bare pomija automatyczne wczytywanie hooków, skilli, pluginów, serwerów MCP i CLAUDE.md; --setting-sources "" nie wczytuje żadnego pliku ustawień, więc nie obowiązują ani ustawienia repozytorium, ani twoje ustawienia użytkownika (z ich blokiem env i regułami allow), a --strict-mcp-config ignoruje jego .mcp.json. Te dwie flagi domykają to, co sam tryb bare zostawia otwarte, i utrzymują zamiar jawnym, jeśli kolejne wydanie zmieni to, co czyta tryb bare. I nigdy nie uruchamiaj takiego zadania z sekretami w środowisku, do których może sięgnąć kod z repozytorium.

--bare kończy się błędem uwierzytelniania. Tryb bare nigdy nie czyta loginu do subskrypcji. Naprawa: wyeksportuj ANTHROPIC_API_KEY albo zrezygnuj z --bare i zaakceptuj, że lokalna konfiguracja się załaduje.

Parser psuje się na nowym sformułowaniu. Wyjście tekstowe różni się między przebiegami. Naprawa: przejdź na --output-format json z --json-schema i czytaj structured_output.

Pętla ponowień kończy się przy pierwszym błędzie. Przy set -e zwykłe result=$(claude -p …), które się nie powiedzie, kończy skrypt, zanim dojdzie do logiki ponowień. Naprawa: sprawdzaj polecenie wewnątrz &&, || albo if, tak jak robi to wrapper powyżej.

/release uruchamia coś innego. Skill i plik polecenia o tej samej nazwie rozwiązują się do skilla, a osobisty skill w ~/.claude/skills/ wygrywa ze skillem projektu o tej samej nazwie, więc na twoim laptopie skrypt może uruchomić inny plik niż na maszynie z cronem. Naprawa: nadawaj skillom automatyzacji konkretne nazwy, na przykład /release-prep, i wpisz / w sesji, żeby zobaczyć, do czego rozwiązuje się dana nazwa.

Zadanie zostaje zabite i zostawia połowę zmiany. SIGTERM kończy proces kodem 143 i nie zapisuje wyniku. Naprawa: wysyłaj SIGINT, żeby tura mogła się zakończyć, i zawsze uruchamiaj zadania na gałęzi, żeby git checkout -- . było bezpiecznym resetem.