Summary
session-start.sh and prompt-inject.sh (and likely the other hook shims using
the same pattern) fail with exit code 2 and completely empty stdout/stderr
when CLAGENTIC_LITE_HOME is set to a directory that doesn't contain
scripts/platform.sh. Claude Code surfaces this as "No stderr output," which
gives the user no actionable signal — the hook just silently blocks every
prompt.
Confirmed still present on current HEAD (a22e1a4, 2026-08-14), i.e. not
fixed by a normal clagentic-lite update.
Root cause
Both hooks do:
: "${CLAGENTIC_LITE_HOME:=/home/jwest/.clagentic/lite}"
. "$CLAGENTIC_LITE_HOME/scripts/platform.sh" 2>/dev/null || true
- The
:= default only applies when the var is unset. It's a no-op if
the var is set to any wrong/stale value — there's no validation that
CLAGENTIC_LITE_HOME actually resolves to a real checkout.
- Under POSIX sh/dash,
. (source) is a special builtin. A "file not
found" error inside a special builtin is a fatal shell error that
terminates the script immediately. || true cannot catch it (it only
fires on a normal nonzero exit, not a special-builtin fatal abort), and
the preceding 2>/dev/null swallows dash's own diagnostic before it
ever reaches Claude Code's hook runner. Net effect: exit 2, no stdout,
no stderr, completely undiagnosable from the user's side.
This is easy to hit in practice: it's exactly what happens when a user has
a stale CLAGENTIC_LITE_HOME (or CLAGENTIC_HOME) left over from before the
env-var/path rename in fd7c3bc (lr-e84c), or any other environment drift
that leaves the var pointing at a directory that no longer exists.
Repro
env -i CLAGENTIC_LITE_HOME=/tmp/nonexistent-clagentic
/path/to/.claude/hooks/session-start.sh
echo $?
# -> 2, zero bytes on both stdout and stderr
Same result for prompt-inject.sh.
Suggested fix
- Before sourcing anything, validate that CLAGENTIC_LITE_HOME points at a
real checkout (e.g. test -f "$CLAGENTIC_LITE_HOME/scripts/platform.sh")
and print a clear message to stderr + exit nonzero with an actionable
hint if not, e.g.:
"clagentic-lite: CLAGENTIC_LITE_HOME=$CLAGENTIC_LITE_HOME has no
scripts/platform.sh — check ~/.bashrc and ~/.config/clagentic/config for
a stale path (run clagentic-lite doctor)."
- Avoid
. "$X" 2>/dev/null || true as a "make missing-file source
non-fatal" idiom under dash/POSIX sh generally — it does not work for
special builtins. Guard with an explicit [ -f "$X" ] && . "$X" instead.
doctor already has a fairly good "env var migration" check (added
recently) that catches this exact class of drift when the user runs it
directly — but the hooks themselves have no equivalent guard, so a
user hits total silence before ever thinking to run doctor.
Environment
- clagentic-lite install at ~/.clagentic/lite, HEAD a22e1a4 (2026-08-14).
- Originally discovered via a stale CLAGENTIC_LITE_HOME left in ~/.bashrc
after the CLAGENTIC_HOME -> CLAGENTIC_LITE_HOME / ~/.clagentic-lite ->
~/.clagentic/lite rename (fd7c3bc, lr-e84c). Reproduced independently of
that specific cause via the env -i repro above, confirming it's a
general hook robustness gap, not specific to that one rename.
Summary
session-start.sh and prompt-inject.sh (and likely the other hook shims using
the same pattern) fail with exit code 2 and completely empty stdout/stderr
when CLAGENTIC_LITE_HOME is set to a directory that doesn't contain
scripts/platform.sh. Claude Code surfaces this as "No stderr output," which
gives the user no actionable signal — the hook just silently blocks every
prompt.
Confirmed still present on current HEAD (a22e1a4, 2026-08-14), i.e. not
fixed by a normal
clagentic-lite update.Root cause
Both hooks do:
: "${CLAGENTIC_LITE_HOME:=/home/jwest/.clagentic/lite}"
. "$CLAGENTIC_LITE_HOME/scripts/platform.sh" 2>/dev/null || true
:=default only applies when the var is unset. It's a no-op ifthe var is set to any wrong/stale value — there's no validation that
CLAGENTIC_LITE_HOME actually resolves to a real checkout.
.(source) is a special builtin. A "file notfound" error inside a special builtin is a fatal shell error that
terminates the script immediately.
|| truecannot catch it (it onlyfires on a normal nonzero exit, not a special-builtin fatal abort), and
the preceding
2>/dev/nullswallows dash's own diagnostic before itever reaches Claude Code's hook runner. Net effect: exit 2, no stdout,
no stderr, completely undiagnosable from the user's side.
This is easy to hit in practice: it's exactly what happens when a user has
a stale CLAGENTIC_LITE_HOME (or CLAGENTIC_HOME) left over from before the
env-var/path rename in fd7c3bc (lr-e84c), or any other environment drift
that leaves the var pointing at a directory that no longer exists.
Repro
env -i CLAGENTIC_LITE_HOME=/tmp/nonexistent-clagentic
/path/to/.claude/hooks/session-start.sh
echo $?
# -> 2, zero bytes on both stdout and stderr
Same result for prompt-inject.sh.
Suggested fix
real checkout (e.g. test -f "$CLAGENTIC_LITE_HOME/scripts/platform.sh")
and print a clear message to stderr + exit nonzero with an actionable
hint if not, e.g.:
"clagentic-lite: CLAGENTIC_LITE_HOME=$CLAGENTIC_LITE_HOME has no
scripts/platform.sh — check ~/.bashrc and ~/.config/clagentic/config for
a stale path (run
clagentic-lite doctor).". "$X" 2>/dev/null || trueas a "make missing-file sourcenon-fatal" idiom under dash/POSIX sh generally — it does not work for
special builtins. Guard with an explicit
[ -f "$X" ] && . "$X"instead.doctoralready has a fairly good "env var migration" check (addedrecently) that catches this exact class of drift when the user runs it
directly — but the hooks themselves have no equivalent guard, so a
user hits total silence before ever thinking to run doctor.
Environment
after the CLAGENTIC_HOME -> CLAGENTIC_LITE_HOME / ~/.clagentic-lite ->
~/.clagentic/lite rename (fd7c3bc, lr-e84c). Reproduced independently of
that specific cause via the env -i repro above, confirming it's a
general hook robustness gap, not specific to that one rename.