Przejdź do głównej zawartości

Skryptowanie Claude Code to uruchamianie claude -p ze skryptu powłoki, hooka git, zadania cron lub kroku CI zamiast sesji interaktywnej. Taki przebieg startuje w trybie Manual (od v2.1.285 w trybie auto u zewnętrznych dostawców lub bez telemetrii) 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, z wyjątkiem zmian z v2.1.285 i v2.1.286 w punktach 1 i 5, które pochodzą z changelogu Claude Code (sprawdzone 2026-10-12).

  1. Startuje w trybie Manual na każdym planie. Od v2.1.283 (oba kanały wydań na 2026-10-12) tryb auto jest domyślny w sesjach interaktywnych, ale nie w -p, z wyjątkiem zewnętrznych dostawców i sesji z wyłączoną telemetrią, gdzie -p startuje w trybie auto od v2.1.285. W trybie Manual 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. Od v2.1.286 łączy się też wyłącznie z serwerami MCP wskazanymi w wierszu poleceń, nie wysyła przypomnień systemowych i nie uruchamia zadań w tle. 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, co wymagałoby pytania, i właśnie tego chcesz, gdy nikt nie patrzy: odczyty w katalogach roboczych i polecenia tylko do odczytu nadal działają, a resztę dodają twoje reguły allow.

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 — run one unattended Claude Code job; exit non-zero unless it succeeded.
# Usage: scripts/claude-job.sh "PROMPT" [extra claude flags...]
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
# A result object means Claude ran and stopped on purpose: retrying will not help.
jq -e '.type == "result"' "$OUT" > /dev/null 2>&1 && break
[ "$attempt" -lt 3 ] || break # no sleep after the last attempt
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 # a denied call fails the job unless the caller opts in
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
# Explain a failing build without letting Claude touch anything
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."
# A project-specific typo linter as an npm script (from the headless docs)
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."
# A changelog entry from commits since the last tag
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 — block the commit on a critical finding in the staged diff
set -euo pipefail
diff=$(git diff --cached --no-color)
[ -z "$diff" ] && exit 0
gitleaks git --staged # deterministic secret scan first; exits 1 on a leak and blocks the 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" # cron's PATH lacks the native install
source "$HOME/.config/claude-cron.env" # exports CLAUDE_CODE_OAUTH_TOKEN
cd /srv/checkouts/billing-api # a checkout no human works in
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 # nothing changed
git push -q -f origin chore/dep-audit
gh pr create --fill --head chore/dep-audit 2> /dev/null || true # reuses the open PR on later weeks

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 (od v2.1.285 w trybie auto u zewnętrznych dostawców lub z wyłączoną telemetrią), 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.

Serwer deweloperski w tle zatrzymuje się po 30 minutach albo zadanie na niego czeka. W sesji bez nadzoru (-p, Agent SDK, CI albo sesja w chmurze) polecenie Bash lub PowerShell w tle zatrzymuje się po upływie limitu czasu: timeout, który Claude przekazuje z run_in_background, albo domyślnie 30 minut, najwyżej 2 godziny. W przebiegu -p, w którym prompt podajesz jako tekst, oba domyślne limity wynoszą 10 minut, a przebieg pozostaje otwarty po wyniku, dopóki polecenie w tle uruchomione przez główną rozmowę nie zakończy się albo nie osiągnie tego limitu. Limit pojawił się w v2.1.285 i do v2.1.288 obowiązywał w każdej sesji, więc wersje od v2.1.285 do v2.1.287 zatrzymują też polecenia w tle w interaktywnym terminalu; od v2.1.288 (oba kanały wydań na 2026-10-17, bo stable to 2.1.292) sesje w terminalu, w aplikacji desktopowej i w VS Code nie mają limitu. Naprawa: uruchamiaj długo działające usługi w osobnym kroku CI, poza Claude Code, albo podnieś limit przez BASH_DEFAULT_TIMEOUT_MS powyżej 1800000 (powyżej 600000 dla promptu tekstowego) lub BASH_MAX_TIMEOUT_MS powyżej 7200000; niższa wartość nigdy nie skraca limitu. Źródło: dokumentacja narzędzi Claude Code i trybu headless, sprawdzona 2026-10-12.

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.