# Contributor handoff — Graphify-Labs/graphify

> Canonical page: https://codevetter.com/unpack/graphify/agent-handoff

# Contributor handoff — Graphify-Labs/graphify

Scanned commit 20a20d30d8e7eef77675651f0199d87f913bd3e7 (2026-09-20). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Read ARCHITECTURE.md first — its module table is enforced by a test. Then skim __main__.py (dispatch + re-exports), cli.py::dispatch_command (command table), extract.py (_get_extractor/_DISPATCH + the resolver tail), and paths.py (output-dir constants, atomic writes, cross-platform path helpers). Run `uv sync --all-extras --frozen` then `pytest tests/ -q`. Conventions: issue-numbered comments, atomic writes via paths.write_*_atomic, never cache zero-node extractions, keep the __main__ re-export surface stable, and never edit generated skill*.md files — edit tools/skillgen/fragments and regen.
- First reads: ARCHITECTURE.md (pinned by tests/test_architecture_doc.py), graphify/__main__.py, graphify/cli.py dispatch_command, graphify/extract.py's _get_extractor/_DISPATCH and LanguageResolver registration block, graphify/paths.py, and graphify/security.py. — [ARCHITECTURE.md](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/ARCHITECTURE.md) [graphify/cli.py#L1064](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/cli.py#L1064) [graphify/extract.py#L6502-6545](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/extract.py#L6502-L6545) [graphify/paths.py](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/paths.py) [graphify/security.py](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/security.py)
- Build/test: `uv sync --all-extras --frozen` (lock is committed; CI forbids re-resolving), `uv run --frozen pytest tests/ -q`; lint is a minimal ruff ruleset (E9,F63,F7,F82), pyright basic mode on graphify+tests; skill artifact drift check is `python -m tools.skillgen --check`. — [.github/workflows/ci.yml#L33-74](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/.github/workflows/ci.yml#L33-L74) [pyproject.toml#L160-174](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/pyproject.toml#L160-L174)
- graphify/skill*.md, graphify/skills/*/references/*.md, and graphify/always_on/*.md are GENERATED — never hand-edit; change tools/skillgen/fragments/, run `python -m tools.skillgen`, and let --check/--audit-coverage/--monolith-roundtrip verify. — [tools/skillgen/gen.py#L1-25](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/tools/skillgen/gen.py#L1-L25) [pyproject.toml#L144-150](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/pyproject.toml#L144-L150)
- Import direction rule: graphify/extract.py imports from graphify/extractors/, never the reverse; extractor ports must be verbatim byte-identical moves, one language per PR, with a facade re-export kept in extract.py. — [graphify/extractors/MIGRATION.md#L36-61](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/extractors/MIGRATION.md#L36-L61)
- All file writes to graphify-out/ artifacts go through paths.write_text_atomic/write_json_atomic (temp file + os.replace + os_replace_with_fallback for Windows); never Path.write_text for graph.json/manifest/labels. — [graphify/paths.py#L101-165](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/paths.py#L101-L165)
- Never cache a zero-node extraction result — extract.py deliberately skips save_cached when an extractable file returns no nodes so reruns self-heal; mirroring that, _stamped_manifest_files must stay the chokepoint deciding which files count as 'done'. — [graphify/extract.py#L6595-6602](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/extract.py#L6595-L6602) [graphify/cli.py#L88-168](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/cli.py#L88-L168)
- extract(paths, root=...) : always pass root explicitly — without it node ids/source_file anchor to the common parent of the passed list, baking machine-specific path segments into portable graph.json artifacts. — [ARCHITECTURE.md#L36-48](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/ARCHITECTURE.md#L36-L48) [graphify/extract.py#L6787-6893](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/extract.py#L6787-L6893)
- __main__.py's re-export list is a public API: install and cli symbols are re-imported there so `from graphify.__main__ import X` keeps working — do not remove names or move dispatch without preserving the re-exports. — [graphify/__main__.py#L27-131](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/__main__.py#L27-L131)
- Stored/portable paths must be classified with paths.is_absolute_any_platform (POSIX+Windows), not Path.is_absolute — the corpus travels between OSes; but live-filesystem resolution keeps using Path.is_absolute. — [graphify/paths.py#L378-410](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/paths.py#L378-L410)
- Edge/node conventions to preserve: confidence is exactly EXTRACTED|INFERRED|AMBIGUOUS; generic relations (references/uses/mentions) must lose edge-collapse to specific ones; import-family edges to undeclared targets mint `external` stub nodes; source_file is stored relative to the SCAN root. — [ARCHITECTURE.md#L50-73](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/ARCHITECTURE.md#L50-L73) [graphify/build.py#L56-137](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/build.py#L56-L137)
- Trap: `graphify query` keeps the loaded graph undirected (BFS needs callers+callees) while path/explain force directed; edge direction lives in _src/_tgt per-link markers — do not 'simplify' either side without reading the #2309 comments. — [graphify/cli.py#L1259-1284](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/cli.py#L1259-L1284) [graphify/serve.py#L56-76](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/serve.py#L56-L76)
- Hook/hook-guard payloads must stay shell-agnostic (pure `graphify` subcommand calls, no bash syntax) and the embedded python -c rebuild bodies must not contain `"`, `$`, backtick or backslash — constraints are documented inline and enforced by tests like test_hook_guard/test_hooks. — [graphify/hooks.py#L140-145](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/hooks.py#L140-L145) [graphify/__main__.py#L273-282](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/graphify/__main__.py#L273-L282) [tests/test_hooks.py](https://github.com/Graphify-Labs/graphify/blob/20a20d30d8e7eef77675651f0199d87f913bd3e7/tests/test_hooks.py)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
