English | 한국어
Which tests does this change affect, and what depends on this file? Ziplex answers from a zero-config dependency graph — for your CI, your editor hook and your coding agent.
Ziplex parses a project with Tree-sitter and resolves imports the way the toolchain does — relative/index files, tsconfig paths aliases, pnpm/npm workspace packages and their exports, Python packages, re-exports, conftest.py and package __init__.py files, Go packages — into one graph across languages. It keeps that graph in an incremental local index (no LLM, no network, no API key) and answers from it in milliseconds.
⚠️ Under active development. Interfaces may still change.
- Running only the tests a change can affect — locally (
pytest $(ziplex impact --format paths)) or on every pull request (CI template). Measured on 99 real commits of repos Ziplex was never tuned on: recall 0.976, or 0.988 without the imports pytest itself makes (eval). It falls back to the full suite whenever a targeted run isn't safe. - Giving a coding agent the impact answers grep can't produce in one step —
ziplex-mcpanswers "which tests cover this change", "what is transitively affected", "how does A reach B". On held-out repos, Claude Code with it spent 57% less and finished 55% faster on those questions, at the same accuracy (EXPERIMENTS #15). - Polyglot and monorepo codebases — a TypeScript frontend, a Python backend and shared workspace packages resolve into one graph, with no per-language tool to configure.
- An editor hook — after Claude Code edits a file, one line tells it how many files depend on it and which tests to run.
Honest scope: for a direct "who imports X" question a single grep is already enough (the MCP costs ~12% more there), and in small, local bug fixes agents gained nothing measurable from it (EXPERIMENTS #16). The value is in transitive impact and test selection.
pip install ziplex # or: pipx install ziplex
cd your-project
ziplex impact # tests affected by your uncommitted changes
pytest $(ziplex impact --format paths) # run just those (prints nothing -> full suite when unsure)
ziplex deps src/app.py --in --depth 2 # who depends on a file, by hop
ziplex install claude --hook # register the MCP server + post-edit hook with Claude CodeThe first command builds .ziplex/index.db (gitignored automatically; django's 5,700 files take ~10s, later updates under a second). More in Graph index, MCP server and the CI template.
pip install ziplex # the graph: index, deps, impact, path, MCP server, editor hook
pip install "ziplex[llm]" # + LLM-written summaries for `ziplex pack` (requests, python-dotenv, tiktoken)
pip install "ziplex[gui]" # + the read-only viewer `ziplex-gui` (flask, pywebview, watchdog)
pip install "ziplex[all]" # bothpipx install ziplex keeps it in its own environment with the commands on PATH. On Windows, if ziplex isn't found after a plain pip install, pip installed per-user into a Scripts folder that isn't on PATH (it prints a warning saying which) — add that folder to PATH or use pipx.
No pack and no LLM: these commands keep an incremental dependency-graph index in <project>/.ziplex/index.db (a disposable cache, gitignored automatically) and answer from it. The project defaults to the current directory.
ziplex index [--check] # build/refresh the index; --check exits 1 if anything changed
ziplex deps src/app.py # what it imports (with line numbers)
ziplex deps src/app.py --in --depth 2 # who depends on it, by hop
ziplex impact # tests affected by your uncommitted changes (= --diff worktree)
ziplex impact --diff origin/main...HEAD # ... by a branch
pytest $(ziplex impact --format paths) # run just those tests
ziplex path src/app.py src/db.py # shortest import chain
ziplex tree . # the whole dependency treeWhat it resolves: relative and index-file imports, tsconfig/jsconfig paths and baseUrl, pnpm/npm/yarn workspace packages and their exports (conditions, wildcards), Python packages from any source root (src-layout included), re-exports through __init__.py, Go packages via go.mod, C/C++ includes, Godot res:// references, plus prose mentions of file paths in docs and configs (kept separate, never counted as dependents). Tests are found by each runner's own conventions; conftest.py and package __init__.py files count as executed-before-the-test, imports under if TYPE_CHECKING:/import type/__main__ guards don't, and a test reached only through a function-local import is reported as possibly affected.
impact --format paths prints nothing when a targeted run isn't safe (a build/config/lockfile changed, or a file was deleted), so the pytest $(...) line falls back to the whole suite; the reason goes to stderr. --format commands prints ready-to-run pytest/jest/vitest/go test commands; --format json everything.
CI: docs/ci/impacted-tests.yml runs only the affected tests on a pull request and the full suite when needed. Keep a full run on main or nightly — dynamic imports (importlib, plugin registries) are invisible to any static graph.
Editor hook: ziplex install claude --hook registers the MCP server and adds a PostToolUse hook (ziplex-hook) to <project>/.claude/settings.json. After Claude edits a file it gets one line: how many files depend on it and which tests to run. It never blocks, stays silent outside indexed projects, and repeats at most once per file per 10 minutes. --dry-run shows the command and the settings diff without changing anything.
Measured: recall 0.976 on 99 real commits of held-out repos for impacted tests; index build ~10s for django's 5,700 files, under a second to stay current.
ziplex-mcp gives Claude Code, Cursor or any MCP client the same live graph — no pack needed, refreshed from disk before every call.
claude mcp add ziplex -- ziplex-mcp --project /abs/path/to/project # or: ziplex install claude| Tool | What it answers |
|---|---|
graph_overview(scope?) |
Hubs, import cycles, folder layering, unresolved relative imports — start here in an unfamiliar repo |
who_depends_on(files, depth?, include_mentions?) |
Who imports these files (with the import line), or everything transitively affected, by hop |
dependencies_of(files, external?) |
What these files import, resolved to files |
impacted_tests(files?, diff?) |
Tests affected by a change or a git diff, with the import chain and a ready-to-run command |
dependency_path(source, target) |
The shortest import chain between two files |
Answers are compact text (tens to a few hundred tokens); the five tool definitions cost ~720 tokens per session. On held-out repos, Claude Code with these tools answered impacted-tests questions at 57% lower cost and 55% faster, with the same accuracy (EXPERIMENTS #15).
Legacy mode. ziplex-mcp --aif <name>.json [--project .] (or --legacy-tools) serves the previous ten tools over a packed aif.json (get_overview, list_files, get_folders, get_relationships, get_graph_summary, get_dependents, get_blast_radius, get_detail, check_freshness, search_project).
ziplex pack writes a project's shape into one portable file: per-file summaries, inferred coding rules, an AI guide, a folder map and the resolved relationships — useful for pasting into a chat that has no tool access, committing next to the code, or browsing in the GUI. For agents that do have tools, the graph above is what measurably helps; LLM summaries did not beat a tool-using agent (EXPERIMENTS #1-#9).
ziplex pack ./your-project --no-llm # no API key: structural summaries (signatures/dependencies per file)
ziplex pack ./your-project # LLM-written summaries, rules and guide (needs ziplex[llm] + a provider key)Packing is non-interactive: every file that passes the secret scan is packed; a flagged file's content is never included, but its imports still appear in the graph. Unchanged files reuse their summaries by content hash, LLM summaries are cached as they arrive (an interrupted pack loses nothing), and a repeat pack with nothing changed exits immediately.
| Flag | Effect |
|---|---|
--no-llm |
Structural summaries only; no API key or network |
--no-cache |
Re-summarize everything |
-o, --output <path> |
Output path (plus sibling .detail.json/.cache.json); default <project>/.ziplex/<name>.json |
--include / --ignore <patterns> |
Comma-separated globs on top of .ziplex.json |
--lang en|ko |
Language the summaries/rules/guide are written in |
--max-tokens N (+ --max-tokens-model M) |
Exit 1 if the saved aif.json exceeds N tokens |
LLM providers
| Provider | LLM_PROVIDER |
Config |
|---|---|---|
| Gemini (default) | gemini |
GEMINI_API_KEY, optional GEMINI_MODEL |
| OpenAI-compatible — OpenAI, Ollama, LM Studio, vLLM, OpenRouter, Groq, llama.cpp | openai |
OPENAI_API_KEY (often unneeded locally), OPENAI_BASE_URL, OPENAI_MODEL |
| Claude | claude |
ANTHROPIC_API_KEY, optional CLAUDE_MODEL |
Set them in a .env, the environment, or with ziplex settings set <key> <value> (~/.ziplex/settings.json). A local model through Ollama/LM Studio is the openai provider with OPENAI_BASE_URL=http://localhost:11434/v1 (Ollama) or http://localhost:1234/v1 (LM Studio).
Output format
| File | Contains |
|---|---|
aif.json |
Project guide, coding rules, folder map, token stats, one summary per file, certain dependency edges |
<name>.detail.json |
The compressed source per file (function bodies elided as ⋮----) and prose mentions (text_refs) |
<name>.cache.json |
A content hash per packed file, for freshness checks and incremental re-packs |
Exports. ziplex skill <name>.json writes a Claude Agent Skill (.claude/skills/<slug>/) that Claude Code loads on its own; ziplex flatten <name>.json writes one Markdown file with every summary and compressed body inline.
Team use. The pack is just files — commit them like any generated artifact. ziplex freshness <project> <name>.cache.json exits non-zero when the committed pack has drifted from the code (CI template); on a conflict, re-pack instead of hand-merging (merge-conflicts.md, gitattributes).
ziplex init ./your-project scaffolds .ziplex.json in the target project:
{
"include": ["src/**/*.py", "*.md"], // empty = everything not ignored
"ignore": ["**/*.generated.*"], // on top of the built-in ignores and .gitignore
"exclude_flagged_from_graph": false // true: drop secret-flagged files from the graph too
}The graph index, pack, tree and freshness all read it.
ziplex-gui (needs ziplex[gui]) is a local, read-only viewer for a packed project: overview, file tree with summaries and compressed source, dependents and blast radius, the dependency graph, search, live freshness badges. Pack with ziplex pack, then open the resulting aif.json. Binds to 127.0.0.1 only.
| Command | Description |
|---|---|
settings / settings set <key> <value> |
View/change ~/.ziplex/settings.json (LLM provider, model, keys) |
doctor [<path>] |
Environment check — Python, LLM provider/key, secretlint |
dev collect|tokens|search|detail|signatures|dependencies|api|compress|debug ... |
Debug tools for one step of the pipeline |
--version |
Installed version (also ziplex-mcp --version) |
A bare ziplex prints the command list.
Every direction decision is backed by a recorded comparison: docs/EXPERIMENTS.md (16 rounds, including the negative results), eval/ (edge-accuracy ground truth, impacted-tests recall on real commits, headless agent comparisons) and the 2026-10 review that set the current direction.
pip install -e ".[dev]"
pytestNothing in the suite calls an LLM or the network. LLM_PROVIDER=mock ziplex pack <project> smoke-tests the LLM path offline.
Python 3.10+ · Tree-sitter (Python/Java/TypeScript/JavaScript/Lua/GDScript/Go/C++/Rust/C#/PHP/Ruby/Bash) · SQLite · MCP · pathspec · ruamel.yaml · optional: requests (Gemini / OpenAI-compatible / Claude), tiktoken, Flask, pywebview, watchdog · secretlint if installed


{ "project": { "name": "...", "prompt": "...", "tech_stack": [...], "security_scan": { "flagged": 0, "included_anyway": 0, "excluded": 0 }, "scope": { "include": [], "ignore": [] }, "format_notes": "...", "language": "en", "ziplex_version": "0.7.0", "llm": true }, "rules": ["..."], "folders": { "src": { "summary": "...", "file_count": 12 } }, "tokens": { "GPT-4o": { "original": 3100, "compressed": 749, "saved_pct": 75.8 } }, "files": { "src/App.tsx": { "summary": "..." } }, "relationships": { "src/App.tsx": { "internal": ["..."], "external": ["react"] } } }