Apache 2.0 adds an explicit patent grant, a patent-retaliation clause,
and explicit inbound-contribution terms. MIT's sublicense right permits
relicensing the combined work, so this needs no per-contributor consent;
prior contributions were made under MIT and remain available under those
terms. The original MIT text is retained in LICENSE-MIT and referenced
from NOTICE.
- LICENSE: verbatim Apache License 2.0
- LICENSE-MIT: preserved MIT text for prior contributions
- NOTICE: attribution + pointer to LICENSE-MIT
- pyproject: license = "Apache-2.0" (PEP 639 SPDX), license-files, setuptools>=77
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The .graphifyinclude loader and its two matcher helpers had no consumers:
commit df40e4d (#873, index dot dirs) removed the blanket dot-prefix
exclusion and with it the only call sites, leaving detect() parsing the
file on every run and then discarding the result. A .graphifyinclude was
silently a no-op.
Delete _load_graphifyinclude, _is_included, _could_contain_included_path
and the orphaned assignment; add .graphifyinclude to _SKIP_FILES so a
leftover file no longer lands in unclassified; and print a one-time
stderr note when one is present at the scan root, pointing to ! negation
patterns in .graphifyignore. Bump to 0.9.25.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Homepage/Repository/Issues were stale from the org move (safishamsi/graphify).
Aligning them to Graphify-Labs/graphify fixes the PyPI "Issues" link and is a
prerequisite for PyPI to mark the Repository link Verified once releases publish
via a GitHub trusted publisher.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agents routinely ignore the advisory "run graphify query first" nudge and read
raw files anyway. `graphify install --project --strict` (or `graphify claude
install --strict`) now installs a hook that BLOCKS the first raw source read of a
session via permissionDecision:"deny" with a redirect to graphify query, then
downgrades to the soft nudge — it fires at most once per session (atomic
per-session marker) so it can never strand the agent, and a recent
query/explain/path refreshes a stamp that suppresses it. Claude Code only;
Bash-grep and Glob stay nudge-only; Gemini/Codex/OpenCode are unchanged.
GRAPHIFY_HOOK_STRICT=1/0 toggles at runtime without a reinstall; default installs
are byte-identical (soft nudge).
Also fixes#1840 for the default soft nudge: the guard no longer fires for reads
of out-of-project files, and softens to a non-mandatory nudge when the graph is
stale for the target file. Gating is ~3 stat calls (no corpus walk) and fails
open. Begins the 0.9.19 cycle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bumps to 0.9.17 (unreleased) and records the batch implemented via Fable
subagents in isolated worktrees, integrated onto v8: out-of-scope node
drop, manifest stamping, merge-driver registration, hooksPath configparser
fix, obsidian prune, multilingual query stopwords, .skill classification,
and the postgres package-name hint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The #1757 batch-scoping followup built the per-chunk allowlist by reading
FileSlice.rel, which does not exist (a FileSlice carries its parent file
in .path). So every chunk containing a sliced oversized document leaked
the FileSlice object into the allowlist, save_semantic_cache raised
TypeError on Path(FileSlice), and the best-effort except swallowed it:
extraction finished but those chunks were never checkpointed, so a
re-run or a crash/rate-limit resume re-billed them.
Resolve each unit through the canonical unit_path() helper so a slice
maps to its parent file. Adds a regression test that slices a real
oversized .md and asserts the checkpoint writes without swallowing a
TypeError.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The HTML report's neighbor "focus" links dropped an unescaped
JSON.stringify(nid) into a double-quoted inline onclick. The stringified
value carries its own quotes, so the attribute was truncated on every
node (links never worked), and a node id/label containing a double-quote
broke out of the attribute and injected live event handlers. AST ids are
[a-z0-9_]-safe, but ids/labels from documents or titles scraped via
`graphify add <url>` are not, so a hostile source could plant an
executable handler into a locally-opened report.
Carry the id in an HTML-escaped data-nid attribute and dispatch via one
delegated listener bound to document (survives the innerHTML rebuild that
recreates #neighbors-list). Closes the injection and repairs the links.
Reported by @edgestack-ai.
Co-Authored-By: edgestack-ai <edgestack-ai@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A solution folder is a virtual grouping, not a file: VS writes its name
as both the display name and the "path" (name == path, no real file).
extract_sln resolved it to an absolute filesystem path anyway and keyed
the node id off that. The CLI id-relativization pass only remaps ids of
real files in the scan set, so a virtual folder never matched and its
absolute id (with the local username) survived into a committed
graph.json.
Detect solution folders (name == path) and key their id/source_file off
the folder name only; real project files still resolve as before. Adds a
regression test asserting the folder node id is relative.
The earlier fix (0.9.13) covered .csproj/.sln file nodes but missed the
virtual folders, so #1789 was closed prematurely; this completes it.
Reported and diagnosed by @fremat79.
Co-Authored-By: fremat79 <fremat79@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_rewire_unique_stub_nodes gated merge targets through _is_type_like_definition,
which rejects any label ending in `)`. So a function referenced from another
module (passed by name, e.g. FastAPI's Depends(get_db)) left its reference edge
dangling on a sourceless name-only stub while the real def had zero incoming
edges — "who references this function" returned nothing. Class/type symbols were
fine; only functions/methods suffered.
Top-level function defs (label `name()`, not `.name()` methods or `Class.m()`
qualifiers) are now eligible rewire targets, but only when:
- the label key matches exactly one such function corpus-wide (existing
unique-candidate guard — two same-named functions stay unresolved), AND
- the candidate shares a language family with the stub's referrers, so a
Python `get_db` reference can't bind to a unique Go `get_db()` (#1718/#1749
interop guard), AND
- the stub is not used as a supertype (inherits/implements/extends) — you
don't inherit from a function.
Types are unchanged. Regression tests: cross-module function ref binds to def;
cross-language, ambiguous, and supertype cases all correctly left unresolved.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two classes with the same simple name in different Maven modules
(FinancialEntryValidator in payment/ and core/) already survive as distinct
path-scoped nodes on v8 -- the "node silently disappears" report from 0.9.9 is
fixed. But a cross-module field/type `references` edge was still left dangling
on a sourceless phantom stub: _resolve_java_type_references (#1318) re-pointed
implements/inherits/extends/imports edges to the real definition using the
importing file's `import` statement, but its REPOINT_RELATIONS omitted
`references`, so bare-name resolution's shadow stub survived for field types.
A query about the referenced class could then miss it.
Add `references` to the Java resolver's REPOINT_RELATIONS. The C# sibling
already covers references; this brings Java to parity. The reference now
resolves to the imported package's class (falling back to same-package), and
the orphaned phantom is dropped. Regression test covers the ambiguous
two-module case: both reals present, no phantom, reference lands on the
imported class.
Reported with a precise root-cause and repro by @aviciot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Decompose extract.py / __main__.py / export.py into focused modules (#1737,
verbatim, no behavior change). Plus fixes since 0.9.10: merge-graphs distinct
repo tags (#1729), uninstall cleans Claude .local files (#1731), and
extract --code-only for keyless code-only indexing of a mixed repo (#1734).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
setuptools uses an explicit package list, so the new graphify/exporters/ package
(base, html, graphdb — split out of export.py) was absent from the built wheel,
which would break `import graphify.exporters.*` for installed users. Add it
alongside graphify and graphify.extractors. No version change.
Verified: fresh-venv install of the rebuilt wheel imports every new module,
resolves all backward-compat re-exports, builds a multi-language graph, and runs
query/path/explain and install/uninstall.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Correctness batch since 0.9.9: TS/JS builtin-typed receiver no longer collapses
onto a same-named user symbol (#1726); no cross-language calls edges (#1718);
build_merge ambiguous-alias no longer merges unrelated files (#1713); base-class
stubs tagged with origin_file (#1707); Java enum constants as nodes (#1719);
rebuild recovers from a deleted hook cwd (#1703); per-chunk semantic-cache
checkpoint (#1715); SECURITY.md http-transport doc + GRAPHIFY_MAX_GRAPH_BYTES
tests (#1714, #1722). Nine merged PRs plus #1726.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes since 0.9.8: explain punctuated-label matching (#1704); surface code files
with no AST extractor instead of dropping them silently (#1689); consistent
AST-extraction progress denominator (#1693); no dangling Obsidian wikilinks in
GRAPH_REPORT.md by default (#1712); MATLAB .m no longer force-parsed by the
Objective-C grammar (#1702); corrected the /graphify usage comment in the skill
files (#1681); surface unclassified files (Dockerfile/Makefile/...) instead of
vanishing (#1692).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
extract_pascal() already imports tree-sitter-pascal for AST-quality
extraction and falls back to a regex extractor when it is absent (#781),
but the grammar was not declared anywhere in the package metadata, so it
was never installed and the AST path never ran out of the box.
Declare a `pascal` extra (and add it to `all`) so users can opt into the
AST extractor with `uv tool install "graphifyy[pascal]"`. tree-sitter-pascal
publishes prebuilt wheels for every platform (win/macOS/Linux), so unlike
the `dm` extra it needs no C toolchain.
On a mid-size Delphi codebase the AST path yields notably more accurate
relationship edges than the regex fallback (calls and inherits both up
~25%). README extras table and uv.lock updated accordingly.
Two 0.9.4 regressions (CLI cross-file indirect_call, stale community labels on
re-cluster), the case-folding god-node fix (#1581), ~15 language extractor
fixes (Ruby/Groovy/Elixir/Fortran/Rust/Julia/SystemVerilog/Scala/PowerShell/
ObjC/PHP/C#/C++/Swift), merge-graphs mixed-type handling (#1606), Swift
singleton-into-local resolution (#1604), Homebrew python@ shebang (#1586),
hooks foreground-stall perf (#1601), serve query stopwords (#1597) and
multi-project MCP serving (#1594), plus JSON-loading hardening, dedup collision
warning, and Windows hook worker limit.
Built wheel validated in a clean venv: CLI reports 0.9.5, import resolves to the
installed package, the case-folding and Swift-singleton fixes verified, and a
real `graphify extract` produces indirect_call + inherits edges end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cross-file member-call resolution for C++/ObjC (#1547/#1556) and
namespace-aware C# type resolution (#1562), the work-memory overlay
(#1441), test-mock call-graph fix (#1553), hyperedge member-key aliases
(#1561), plus the TS/JS/ObjC resolution fixes (#1316/#1544/#1552/#1475).
See CHANGELOG.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ruby type-aware member-call resolution and workspace exports-map
resolution, the #1529 alias/workspace import-edge regression fix, tsconfig
paths fallbacks, semantic-cache pruning, three ObjC extractor fixes, Swift
static-call confidence, the secondary LLM timeout, GraphML null coercion,
host-generic install wording, and Dependabot dep bumps. See CHANGELOG.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`safety` was declared in the dev group but never invoked — the CI
security-scan job only runs bandit and pip-audit, and pip-audit already
provides the same dependency-CVE scanning. Its only practical effect was
pulling in nltk, which carries an unpatched HIGH path-traversal advisory
(GHSA-p4gq-832x-fm9v) with no fix available.
Removing safety drops nltk (and safety-schemas/typer/tenacity/tomlkit)
from the lockfile entirely, closing the alert with no loss of coverage.
Updated the stale CI comment that referenced safety. Full suite green
(2537 passed); pip-audit and bandit unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Patch over 0.9.0: completes the node-ID work (fully closes#1504 via injective
salt #1522), stops origin_file leaking into graph.json (#1516), extends cross-file
stub disambiguation to the six dedicated extractors (#1515), Java type-param skip
(#1518) + record component refs (#1519), prunes a deleted import's edge on update
(#1521), and retries rate-limited (429) requests instead of dropping chunks (#1523).
All non-breaking.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BREAKING: node IDs now include the full repo-relative path (#1504, #1509) — fixes
silent data loss when same-named files live in different directories, and aligns
the AST and LLM id rules. Existing graphs migrate automatically on next build;
`graphify extract --force` to recover previously-collided nodes; Neo4j persisted
stores need a re-import. Also ships the --timing flag (#1490).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0.8.48 added graphify/extractors/ (the per-language split, #1212) but
[tool.setuptools] packages listed only "graphify", so the subpackage was
omitted from the wheel and `graphify extract` raised ModuleNotFoundError on a
fresh install. Editable/dev installs and the test suite import from the source
tree, so it passed CI and local smoke but broke the published package. Add
graphify.extractors to packages; verified the rebuilt wheel imports and extracts
in a clean venv. 0.8.48 is yanked.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
get_community shows the community name (#1448); starlette floored >=1.3.1 for
CVE-2026-48818 / CVE-2026-54283 (#1391, #1396); begin per-language extractor
split into graphify/extractors/ (#1212); parallel community labeling via
--max-concurrency / --batch-size (#1390); reflect dedups dead-ends/corrections;
and the work-memory loop no longer depends on the git hook (reflect --if-stale).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
starlette underpins the HTTP MCP transport (serve_http); graphify/serve.py
imports it directly (Starlette/Middleware/Route) but it was only present
transitively via mcp, with no version floor — so end users installing
graphifyy[mcp] could resolve a vulnerable starlette even after a lockfile bump.
Declare it in the mcp (and all) extras and floor at >=1.3.1, which carries the
fixes for both CVEs (1.3.1 >= the 1.1.0 fix for CVE-2026-48818 and is the fix
for CVE-2026-54283). Lock regenerated 1.0.0 -> 1.3.1.
Supersedes the lock-only bumps in #1391 and #1396 (both targeted 1.3.1 from a
stale base) with a pyproject floor that also protects end users. stdio MCP and
CLI are unaffected. serve/MCP/HTTP tests pass on 1.3.1; full suite 2393 passed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Work-memory (#1441): save-result --outcome + graphify reflect, with recency-decayed
scoring, corroboration threshold, label-matched node-existence gate, contested
handling, and zero-config adoption (skill reads LESSONS.md + records outcomes; git
hooks auto-reflect). Fixes: Python ClassName.method() qualified-call edges (#1446);
validate_extraction/build crash on non-hashable id (#1447); graphify update now
prunes a symbol removed from a surviving file without --force.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`graphify install --platform agents` installs the skill to the generic
Agent-Skills locations: the spec's user-global ~/.agents/skills (global) and
./.agents/skills (--project) — the directories `npx skills` and spec-compliant
frameworks read. `--platform skills` is an alias. Previously that user-global
location was only reachable as an accidental side effect of the gemini-on-Windows
branch. Bare `graphify install` is unchanged (still single-platform claude/windows).
The platform is registered in tools/skillgen/platforms.toml (split, mirroring
amp's agents-md body) and rendered through the skillgen drift/coverage guards.
Since it is a post-v8 platform with no own v8 body, its --audit-coverage baseline
is amp's v8 body (the body it re-homes). The rendered skill body is byte-identical
to amp's; only the on-demand hooks reference differs (its own `graphify agents
install` wording).
The `graphify agents install` / `graphify skills install` subcommand is the
amp-twin: it also wires an AGENTS.md always-on section, keeping it honest with the
hooks reference it points at. The `--platform agents` path stays skill-only,
exactly as amp's `--platform amp` does.
Also: `skill-agents.md` added to package-data, and the wheel-packaging guard now
covers every platform's skill body (not just references/always-on), so a missing
skill body fails CI instead of only breaking install for real users.
Closes#1405. Implements #1432.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pypdf 6.11.0->6.13.3 (CVE-2026-48155/48156), yt-dlp 2026.3.17->2026.6.9,
pyjwt 2.12.1->2.13.0, cryptography 48.0.0->49.0.0, python-multipart
0.0.28->0.0.32, with lower-bound floors for the direct deps (pypdf, yt-dlp) so
installs get the patched versions. Lockfile regenerated for 0.8.42.
Co-Authored-By: hypnwtykvmpr <hypnwtykvmpr@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump version to 0.8.40; document this release in CHANGELOG (PowerShell .psm1
indexing, Swift import survival, no-cluster edge dedup, custom OpenAI/Anthropic
endpoints, JS/TS assignment-form extraction, community-name + --graph fixes,
four production bug fixes, perf, security CI); add .psm1 to the README
supported-extensions table.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>