Repository navigation
bug: absolute paths in manifest.json, .graphify_root, and cache/ast/*.json break git-shared graphify-out/ across machines #777
Description
Problem
Committing graphify-out/ (or $GRAPHIFY_OUT) to git is the documented way to share incremental cache + graph artifacts across a team / CI. Today three artifacts contain absolute paths and break on clone to a different filesystem location:
manifest.json— keys are absolute (/home/alice/proj/foo.py).detect_incrementalcache miss → full rebuild on every other machine. Same observation as Question — manifest.json absolute paths + missing graphify-out/.gitignore: intended or oversight? #722 (filed there as a "question")..graphify_root— absolute project path.graphify updatewith no args fails (or scans the wrong tree) after clone.cache/ast/*.json—source_filefield on cached nodes/edges is absolute. Not directly fatal but pollutes diffs and leaks user paths into commits. Not covered by Question — manifest.json absolute paths + missing graphify-out/.gitignore: intended or oversight? #722.
graph.json is already correctly relativized via watch._relativize_source_files (since 0.5.0) — proves the intent and the pattern.
Filing as a separate bug (rather than commenting on #722) because (a) #722 is question-shaped and limited to manifest + .gitignore, (b) cache/ast/*.json is a distinct artifact with the same root cause, (c) this draft includes a concrete fix + PR offer. Linking #722 to consolidate triage.
Reproduce
mkdir /tmp/p && cd /tmp/p && git init -q && echo "def f(): pass" > a.py
graphify update .
# 1) absolute keys in manifest
python3 -c 'import json; print(list(json.load(open("graphify-out/manifest.json")).keys())[:1])'
# ['/tmp/p/a.py'] ← absolute
# 2) absolute project root
cat graphify-out/.graphify_root
# /tmp/p ← absolute
# 3) absolute source_file in cache/ast
python3 -c 'import json,glob; f=glob.glob("graphify-out/cache/ast/*.json")[0]; d=json.load(open(f)); print({n.get("source_file") for n in d.get("nodes",[])})'
# {'/tmp/p/a.py'} ← absoluteMove /tmp/p to /tmp/q (or clone the committed graphify-out/ on another host): incremental detection misses, root resolution breaks, diffs churn on every rebuild.
Proposed fix
Three small changes mirroring the existing _relativize_source_files, each backwards compatible (relpath fallback to abspath when target escapes root):
graphify/detect.py::save_manifest— relativize keys againstrootbefore serialization. Skip entries whereos.path.relpath(...).startswith("..")(paths outside the root) and write them absolute, matching_relativize_source_files.graphify/watch.py::_rebuild_code— write the user-providedwatch_path(often.) to.graphify_rootinstead of the resolved absolutewatch_root.graphify/cache.py::save_cached— walkresult["nodes"]+result["edges"], relativizesource_filefields againstrootusing the same helper, before JSON dump.
Symmetric loaders (load_manifest, load_cached, __main__ root resolution) re-anchor relative paths against CWD / --root — matches the pattern that already works for graph.json.
Workaround (for context)
Two-way normalize-paths.py PreToolUse/PostToolUse hook flips manifest, root, and cache/ast paths abs↔rel around every graphify invocation. Plus a small runtime shim that patches watch.py to pass manifest_path explicitly. See lib/graphify/install.sh::_patch_graphify_watch and .nvm-isolated/.claude-isolated/hooks/normalize-paths.py in iclaude. Brittle — would rather drop both once upstream lands.
PR offer
Happy to submit a single PR with the three changes + tests (test_save_manifest_relativizes_keys, test_save_cached_relativizes_source_file, test_graphify_root_preserves_relative) after triage / scope confirmation.
Related: #722.
Environment
- graphifyy
0.7.7 - Python 3.12 (uv-managed)
- Project: iclaude (
GRAPHIFY_OUT=.graphifycommitted to git)
Activity
safishamsi commentedon May 18, 2026
Partial progress in 0.8.13:
source_filepaths ingraph.jsonare now relativized at build time viabuild_from_json(root=...)(#932). The three items you raised — manifest.json keys,.graphify_root, andcache/ast/*.jsonsource_file fields — are still absolute and remain open on this issue.fix: make a git-shared graphify-out/ portable across machines (Graphi…
fix: relativize manifest, .graphify_root, and cache source_file fields (
fix: don't resolve symlinks when relativizing manifest/cache keys (Gr…
fix: relativize manifest, .graphify_root, and cache source_file fields (
fix: use relative paths in manifest, .graphify_root, and cache/ast
Write a portable manifest.json from the skill runbooks (#1417)
fix(cache): re-anchor cached ids so a warm hit can't replay another r…
fix(watch): write manifest.json to the target's graphify-out (#2316)
fix: relativize manifest, .graphify_root, and cache source_file fields (
Write a portable manifest.json from the skill runbooks (Graphify-Labs…
fix(cache): re-anchor cached ids so a warm hit can't replay another r…
fix(watch): write manifest.json to the target's graphify-out (Graphif…
Resolve the graphify root marker when GRAPHIFY_OUT is shared and abso…