| 1 |
--- |
| 2 |
name: knowledge-graph |
| 3 |
description: Read and refresh the project's dependency graph to trace classes, services, and modules. |
| 4 |
--- |
| 5 |
|
| 6 |
# Knowledge Graph |
| 7 |
|
| 8 |
A pre-built dependency graph lives at `.claude/graph/dependency-graph.json`. The |
| 9 |
builder is `node bin/build-knowledge-graph.js` (incremental by default, `--full` to force |
| 10 |
rebuild). |
| 11 |
|
| 12 |
This skill has two responsibilities: |
| 13 |
1. **Refresh** the graph at session start if it is stale (`base_commit` ≠ `git rev-parse HEAD`). |
| 14 |
2. **Read** the graph to answer dependency, namespace, and structure questions instantly. |
| 15 |
|
| 16 |
**Read it before** running grep/glob searches for class relationships, namespace |
| 17 |
exploration, or dependency tracing. It eliminates redundant file scans and speeds up the |
| 18 |
first useful response in any session. |
| 19 |
|
| 20 |
--- |
| 21 |
|
| 22 |
## Graph shape |
| 23 |
|
| 24 |
```json |
| 25 |
{ |
| 26 |
"generated_at": "<ISO timestamp>", |
| 27 |
"base_commit": "<git SHA>", |
| 28 |
"node_count": 913, |
| 29 |
"nodes": { |
| 30 |
"classes/Engine/Cache/Subscriber.php": { |
| 31 |
"language": "php", |
| 32 |
"namespace": "Imagify\\Engine\\Cache", |
| 33 |
"symbols": [ |
| 34 |
{ "kind": "class", "name": "Subscriber", "extends": [], "implements": ["SubscriberInterface"] } |
| 35 |
], |
| 36 |
"imports": [ |
| 37 |
"Imagify\\Event_Management\\SubscriberInterface", |
| 38 |
"Imagify\\Engine\\Cache\\Purge" |
| 39 |
] |
| 40 |
} |
| 41 |
}, |
| 42 |
"symbol_index": { |
| 43 |
"Imagify\\Engine\\Cache\\Subscriber": "classes/Engine/Cache/Subscriber.php" |
| 44 |
} |
| 45 |
} |
| 46 |
``` |
| 47 |
|
| 48 |
- **`nodes`** — keyed by relative file path. Each node has the language (`php` or `js`), declared symbols (PHP only), and all import/use statements. |
| 49 |
- **`symbol_index`** — maps every fully-qualified PHP class / interface / trait / enum to its file path. Use this for instant "where is this class?" lookups. |
| 50 |
|
| 51 |
--- |
| 52 |
|
| 53 |
## Query patterns |
| 54 |
|
| 55 |
### Find a class file (zero grep) |
| 56 |
``` |
| 57 |
symbol_index["Imagify\\Engine\\Cache\\Purge"] |
| 58 |
→ "classes/Engine/Cache/Purge.php" |
| 59 |
``` |
| 60 |
|
| 61 |
### Find the ServiceProvider that wires a class |
| 62 |
The ServiceProvider that registers a class imports it. Search for files whose `imports` contain the target FQN: |
| 63 |
|
| 64 |
``` |
| 65 |
filter nodes where "Imagify\\Engine\\Cache\\Purge" ∈ node.imports |
| 66 |
→ "classes/Engine/Cache/ServiceProvider.php" |
| 67 |
``` |
| 68 |
Then read that ServiceProvider to see how the class is registered in `register()`. |
| 69 |
|
| 70 |
### Find all Subscribers in a module |
| 71 |
Filter nodes where: |
| 72 |
- `namespace` starts with the module prefix (e.g. `Imagify\Engine\Cache`) |
| 73 |
- `symbols[*].implements` contains `SubscriberInterface` |
| 74 |
|
| 75 |
### Find all ServiceProviders in the codebase |
| 76 |
Filter nodes where `symbols[*].extends` contains `AbstractServiceProvider`. |
| 77 |
|
| 78 |
### Trace a class's full dependency chain |
| 79 |
1. Start at `symbol_index["Imagify\\...\\ClassName"]` → get file path |
| 80 |
2. Read `nodes[file].imports` → these are its direct dependencies |
| 81 |
3. For each dependency, repeat → you get the full constructor injection tree without reading any PHP |
| 82 |
|
| 83 |
### Verify no unexpected cross-module dependencies |
| 84 |
Check `nodes[file].imports` for any FQN that shouldn't be there. |
| 85 |
For example, a Frontend Subscriber importing an Admin class is a red flag. |
| 86 |
|
| 87 |
### Distinguish modern vs legacy classes |
| 88 |
- Nodes with namespace starting `Imagify\` in `classes/` = modern PSR-4 (`declare(strict_types=1)`). New code goes here. |
| 89 |
- Nodes in `inc/classes/` with classmap prefix `Imagify_` = legacy. Do not add new classes here; migrate out instead. |
| 90 |
- Strauss-prefixed vendor deps appear under `Imagify\Dependencies\` — do not modify. |
| 91 |
|
| 92 |
--- |
| 93 |
|
| 94 |
## Keeping the graph fresh |
| 95 |
|
| 96 |
The graph records the git commit it was built from (`base_commit`). If that SHA differs from `HEAD`, run: |
| 97 |
|
| 98 |
```bash |
| 99 |
node bin/build-knowledge-graph.js |
| 100 |
``` |
| 101 |
|
| 102 |
The script is incremental — it only re-parses files changed since `base_commit`. Use `--full` to force a complete rebuild. |
| 103 |
|
| 104 |
**When to refresh:** |
| 105 |
- At the start of every issue workflow session. |
| 106 |
- After merging a branch with structural changes (new classes, namespace moves). |
| 107 |
- Before an architecture review session. |
| 108 |
|
| 109 |
--- |
| 110 |
|
| 111 |
## Supported languages |
| 112 |
|
| 113 |
| Language | What is extracted | |
| 114 |
|---|---| |
| 115 |
| PHP | `namespace`, `class`/`interface`/`trait`/`enum` declarations (with `extends`/`implements`), `use` imports (including grouped `\{A, B}` forms) | |
| 116 |
| TypeScript / JavaScript | `import` (static + dynamic) and `require()` sources | |
| 117 |
|
| 118 |
--- |
| 119 |
|
| 120 |
## Practical workflow (issue implementation) |
| 121 |
|
| 122 |
Before writing a single line of code for an issue: |
| 123 |
|
| 124 |
1. Check `base_commit` vs `HEAD` — refresh if stale. |
| 125 |
2. Use `symbol_index` to locate all classes involved in the fix. |
| 126 |
3. For each class, read `nodes[file].imports` — know the dependency chain before touching the constructor. |
| 127 |
4. Find the ServiceProvider via the import search above — know where to add/modify the binding. |
| 128 |
5. List all Subscribers in the module — know which ones may need new hook entries. |
| 129 |
6. Check `config/providers.php` to confirm the ServiceProvider is registered. |
| 130 |
7. Only then open the actual PHP files (now you know exactly which ones to read). |
| 131 |
|