Problem
The post-commit and post-checkout hooks installed by graphify hook install run the rebuild synchronously — git commit (and git checkout) does not return until the full repo rebuild completes.
On a moderately large repo (~9k files), the rebuild can take several hours. While it runs:
git commit blocks the developer's shell for the entire duration
- Any tooling that triggers a commit (Claude Code, IDE hooks, automation) stalls or holds open file descriptors
- A subsequent commit before the prior rebuild finishes silently queues another rebuild on the same files
Reproduction (frank-ai-brain, ~9k files):
$ time git commit -m "..."
[graphify hook] N file(s) changed - rebuilding graph...
AST extraction: 1/8903 files (0%)
...
[blocks for 4+ hours]
ps aux showed the rebuild process accumulating 256+ CPU minutes while the parent git commit was still waiting on it.
Why this matters
A post-commit hook should not block the developer's workflow. The rebuild is producing observability output (graphify-out/), not state needed by the next git command. Stalling the developer to update an out-of-band artifact violates the principle that side effects belong out of band.
Suggested fix
Detach the rebuild so the hook returns immediately and the rebuild orphans into the background. Standard portable shell idiom: nohup ... > log 2>&1 < /dev/null & followed by disown.
Patch against graphify/hooks.py _HOOK_SCRIPT:
export GRAPHIFY_CHANGED="$CHANGED"
-$GRAPHIFY_PYTHON -c "
+
+# Run rebuild detached so the commit returns immediately. Full repo rebuild
+# can take hours; blocking the post-commit hook stalls every commit.
+LOG_FILE="$HOME/.cache/graphify-rebuild.log"
+mkdir -p "$(dirname "$LOG_FILE")"
+echo "[graphify hook] launching background rebuild (log: $LOG_FILE)"
+nohup $GRAPHIFY_PYTHON -c "
import os, sys
from pathlib import Path
changed_raw = os.environ.get('GRAPHIFY_CHANGED', '')
changed = [Path(f.strip()) for f in changed_raw.strip().splitlines() if f.strip()]
if not changed:
sys.exit(0)
print(f'[graphify hook] {len(changed)} file(s) changed - rebuilding graph...')
try:
from graphify.watch import _rebuild_code
_rebuild_code(Path('.'))
except Exception as exc:
print(f'[graphify hook] Rebuild failed: {exc}')
sys.exit(1)
-"
+" > "$LOG_FILE" 2>&1 < /dev/null &
+disown 2>/dev/null || true
# graphify-hook-end
Same change for _CHECKOUT_SCRIPT. The rebuild's stdout/stderr go to ~/.cache/graphify-rebuild.log (truncated each run) so users can tail -f it for status.
Result of applying this patch locally
$ time git commit -m "..."
[graphify hook] launching background rebuild (log: /Users/.../.cache/graphify-rebuild.log)
[branch hash] commit message
real 0m0.137s
Down from 4+ hours to 137 ms. Background rebuild continues independently and writes the graph as before.
Optional follow-ups
- Lock file —
~/.cache/graphify-rebuild.lock to prevent two rebuilds from racing if commits land back-to-back.
- Incremental rebuild — if
_rebuild_code already supports incremental updates, the changed-file list (GRAPHIFY_CHANGED) could feed it directly instead of re-walking the whole tree. Would obsolete most of the runtime issue.
- Opt-in flag —
graphify hook install --detached (default) vs --blocking for users who want CI-style commit gating.
Happy to open a PR if the patch shape works for you.
Problem
The
post-commitandpost-checkouthooks installed bygraphify hook installrun the rebuild synchronously —git commit(andgit checkout) does not return until the full repo rebuild completes.On a moderately large repo (~9k files), the rebuild can take several hours. While it runs:
git commitblocks the developer's shell for the entire durationReproduction (frank-ai-brain, ~9k files):
ps auxshowed the rebuild process accumulating 256+ CPU minutes while the parentgit commitwas still waiting on it.Why this matters
A post-commit hook should not block the developer's workflow. The rebuild is producing observability output (
graphify-out/), not state needed by the next git command. Stalling the developer to update an out-of-band artifact violates the principle that side effects belong out of band.Suggested fix
Detach the rebuild so the hook returns immediately and the rebuild orphans into the background. Standard portable shell idiom:
nohup ... > log 2>&1 < /dev/null &followed bydisown.Patch against
graphify/hooks.py_HOOK_SCRIPT:Same change for
_CHECKOUT_SCRIPT. The rebuild's stdout/stderr go to~/.cache/graphify-rebuild.log(truncated each run) so users cantail -fit for status.Result of applying this patch locally
Down from 4+ hours to 137 ms. Background rebuild continues independently and writes the graph as before.
Optional follow-ups
~/.cache/graphify-rebuild.lockto prevent two rebuilds from racing if commits land back-to-back._rebuild_codealready supports incremental updates, the changed-file list (GRAPHIFY_CHANGED) could feed it directly instead of re-walking the whole tree. Would obsolete most of the runtime issue.graphify hook install --detached(default) vs--blockingfor users who want CI-style commit gating.Happy to open a PR if the patch shape works for you.