Skip to content

post-commit hook's npx fallback injects no secrets, so journal generation fails silently without a local package link #93

Description

@wiggitywhitney

Problem

The post-commit hook's npx fallback runs without secret injection, so journal generation fails silently in any repo that does not have a local node_modules/commit-story entry.

scripts/install-hook.sh has two invocation paths. Line numbers below are as of 981b043 (2026-07-21) — match on the code rather than the line if it has moved.

The intended path wraps the call in vals:

# line 105
env -u ANTHROPIC_CUSTOM_HEADERS -u ANTHROPIC_BASE_URL vals exec -f "$REPO_ROOT/.vals.yaml" -- node "${NODE_ARGS[@]}"

The fallback does not:

# line 83
env -u ANTHROPIC_CUSTOM_HEADERS -u ANTHROPIC_BASE_URL npx commit-story

It strips the gateway variables but never injects ANTHROPIC_API_KEY, so it depends on that variable already being in the environment.

Why the fallback gets taken. find_package_dir checks three things: whether the current repo is commit-story, whether $repo_root/node_modules/commit-story is a symlink, and whether it is a directory. It does not check the global npm link. In wiggitywhitney/claude-config, commit-story was globally linked — npm root -g gives /opt/homebrew/lib/node_modules/commit-story -> commit-story-v2 — but there was no local node_modules entry, so PKG_DIR came back empty and the hook fell through to npx.

Why it stayed hidden. ANTHROPIC_API_KEY is present in an interactive terminal but absent inside a Claude Code session, where Datadog-managed settings authenticate via apiKeyHelper rather than a raw key. Hand-made commits journaled correctly; commits made from inside a session did not. The hook backgrounds its work and exits 0, so git reported success either way and no error surfaced.

Observed impact. In claude-config, src/utils/config.js:9 threw ANTHROPIC_API_KEY environment variable is required before anything was written — no journal/entries/2026-08/ directory existed at all. 48 commits since the last successful entry on 2026-07-06 have no journal entry.

Adding vals to the fallback is not sufficient on its own. vals exec hands its child an environment with no PATH:

$ vals exec -f .vals.yaml -- node -p "process.env.PATH"
undefined

A resolved binary like node runs fine, which is why line 105 works. But npx is a script with an env-based shebang, so under vals it fails with env: node: No such file or directory. Confirmed by running the vals-wrapped fallback directly.

Solution

Make the hook reach its working code path rather than depending on ambient environment variables, and consider whether generation failures should be visible.

Directions to choose between:

  • Teach find_package_dir to resolve a globally linked package, e.g. via npm root -g, so the working node + vals path is used when only a global link exists.
  • Make the fallback independent of PATH by invoking node on an absolute resolved path instead of npx. If the fallback keeps npx, it needs both vals and a restored PATH.
  • Decide whether the hook should surface a generation failure rather than exiting 0. Silent success is what allowed this to persist for roughly a month across 48 commits.

Local workaround already applied in claude-config (not a fix for this repo): npm link commit-story, which creates the node_modules entry find_package_dir looks for. Verified — a journal entry generated, along with the backlogged daily, weekly, and monthly summaries.

Acceptance Criteria

  • A repo with commit-story available only as a global npm link generates a journal entry from a post-commit hook run, with no local node_modules/commit-story present
  • The path that runs when no local package entry exists injects secrets from .vals.yaml when that file is present
  • No invocation path relies on ANTHROPIC_API_KEY being inherited from the ambient environment
  • A generation failure is distinguishable from a successful run by someone who only sees the commit succeed
  • The behavior is verified from inside an editor session, not only from an interactive terminal — the two environments differ in exactly the variable that matters

Scope of what was actually verified

Only claude-config demonstrated this failure. Do not assume it is repo-wide.

spinybacked-orbweaver has no journal/entries/2026-08/ directory and looks affected, but it is not — there have been no commits there since 2026-07-29, so there was nothing to journal. That distinction cost time during diagnosis: a missing month directory is explained equally well by "generation is broken" and by "no commits in that month," and only the second is true there. Check commit activity before treating an absent directory as evidence.

No other repos were examined. Whether repos beyond claude-config lack the local package link is unknown.

Checklist

  • Update PROGRESS.md with a changelog entry

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions