phpkg
A code knowledge graph for large legacy PHP codebases — CakePHP 2/3 and Laravel — served to coding agents over MCP.
Legacy PHP defeats both of an AI agent's usual moves. The files are too big to read, and the symbol names are too repetitive to grep. In the codebase this was built against:
| File | Lines | Tokens to read it | get_file method index |
Saving |
|---|---|---|---|---|
OrderRepository.php |
34,053 | ~447,000 | 4,249 | 99.0% |
PaymentsController.php |
30,267 | ~399,500 | — | — |
UsersController.php |
18,395 | ~212,700 | 10,427 | 95.1% |
Reading one of those files can consume an entire context window. Meanwhile
279 methods in that codebase are named index, 230 add, 211 edit — so
grep "function index" returns 279 hits with no way to rank them.
phpkg parses the codebase once with tree-sitter, resolves it into a graph (symbols, callers, routes, model associations, DB-table access), and serves 36 tools over MCP so your agent asks precise questions instead of reading files.
get_symbol("applyScheme") → file + exact start_line/end_line (~200 tokens)
get_callers("applyScheme") → real CALLS_METHOD edges, not text matches
table_consumers("orders") → every reader/writer, across every stack
blast_radius("applyScheme") → what breaks if you change it
Install
Claude Code (plugin — MCP + skill + hooks in one)
/plugin marketplace add ArcXzost/phpkg
/plugin install phpkg@phpkg
Then, in your PHP project:
/phpkg-setup
That detects your stacks, builds the graph, and verifies it. No Python setup —
the plugin bootstraps its own environment via uv.
Any other agent (opencode, Cursor, Zed, Codex…)
uv tool install phpkg # or: pipx install phpkg
phpkg init && phpkg index # in your PHP project
phpkg mcp-config opencode --write
mcp-config supports claude-code, opencode, cursor, zed, codex and
generic. It merges into an existing config rather than overwriting it.
What it indexes
Both stacks, one graph. Many legacy PHP estates run a monolith and a newer framework over the same database. phpkg joins them on physical table nodes, so you can ask what no single-stack tool can answer: if I change this repository, what on the other side of the codebase reads the tables it writes?
| CakePHP 2/3 | Controllers, actions, models, behaviors, components, helpers, templates, routes, shells |
| Laravel | Controllers, Eloquent models, repositories, services, providers, routes, form requests, observers, container bindings |
| Shared | DbTable nodes — the join between stacks |
Convention-driven CakePHP and declaration-driven Laravel get separate resolvers, because they establish structure in opposite directions.
Commands
phpkg init # detect stacks, write phpkg.yaml
phpkg index # build the graph
phpkg watch # incremental reindex on file changes
phpkg serve # start the MCP server
phpkg status # generation, index age, node/edge counts
phpkg summarize # plain-English summaries (see below)
phpkg mcp-config # emit MCP config for a given agent
Reindexing while the server is live
Kuzu takes an exclusive cross-process lock even read-only, so "server running"
and "indexer running" cannot share one database file. phpkg writes each index
run to a new generation and atomically flips a marker; the live server
reopens on its next tool call. phpkg index is safe to run at any time, and
phpkg watch is safe to leave running.
Semantic summaries (optional, no API key)
The graph knows where a method is and what calls it — never what it does.
phpkg summarize fills that in, and your agent writes the prose, so there's
no API key and no per-run cost:
phpkg summarize next <module> -o batch.json # methods + source out
# agent writes {id: sentence} into answers.json
phpkg summarize apply answers.json # summaries in
Summaries survive reindexing for unchanged methods, so a re-run only costs
effort for code that actually changed. Read them back with describe_symbol /
describe_module. The module-level links (cross-module calls, shared tables)
are derived mechanically from existing edges — those cost nothing and work
immediately.
Configuration
phpkg init writes phpkg.yaml. Detection reads composer.json constraints and
layout markers; it never infers a CakePHP major version from a directory name,
because the wrong extractor produces a confidently empty graph rather than an
error. If detection reports ambiguous, set stack: yourself.
repos:
- name: legacy-monolith
root: .
stack: cake2 # cake2 | cake3 | laravel
app_path: app
exclude: [app/Vendor, vendor, app/tmp]
- name: api
root: app/laravel # nested apps are normal
stack: laravel
app_path: app
psr4: { "App\\": "app/" }
When not to use it
Grep is still the right tool for string literals, config values, comments, migrations and template bodies — anything that isn't a PHP symbol. phpkg replaces grep for structure, not for text.
Requirements
Python 3.10–3.13 (Kuzu and tree-sitter have no 3.14 wheels yet). No PHP runtime needed — parsing is static.
Releasing
Publishing runs on PyPI Trusted Publishing (OIDC) — no API token is stored anywhere. Tag and push:
git tag v0.1.0 && git push origin v0.1.0
CI runs the test matrix plus a clean-install job that builds the wheel,
installs it with freshly resolved dependencies, and indexes a real project.
That job exists because the dev tree pins dependencies via uv.lock and
therefore cannot catch a break introduced by a newer release of one — which
is exactly how xxhash 4.0 once produced a silently empty graph.
Status & contributing
Beta. Built against a ~60k-node, ~100k-edge production codebase; broader framework-version coverage is exactly where outside testing helps most. Issues and PRs welcome — especially CakePHP 3/4 and non-standard Laravel layouts.
License
MIT
Metadata
Release files for phpkg 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| phpkg-0.1.0.tar.gz | 326.8 kB | With provenance | Details for phpkg-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| phpkg-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for phpkg-0.1.0-py3-none-any.whl |
Total release size: 486.7 kB
Release files / phpkg-0.1.0.tar.gz
| Download URL | phpkg-0.1.0.tar.gz |
|---|---|
| Size | 326.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5df77bafe8831062a64c2d211ef094e0297db826cd4914bdeda6e6fee99acb13
|
|
BLAKE2b-256 checksum How to use checksums |
cd50934d0b45b743a6e8dc1999bdab9545aed147b6765ef951e4904d256308d6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.
Transparency logRelease files / phpkg-0.1.0-py3-none-any.whl
| Download URL | phpkg-0.1.0-py3-none-any.whl |
|---|---|
| Size | 159.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
69fc7f50f142a34874785a823c979d7c8cc86b8c66cda406f4d5f6000acd753b
|
|
BLAKE2b-256 checksum How to use checksums |
0e5f89f3f60318a61fe879cb1145913af1bd1ef59f84dab4483d62c24555fc67
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.
Transparency logSecurity for phpkg 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for phpkg-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.