Navigate the graph_os knowledge graph before editing load-bearing code. Use when tracing dependencies, planning a rename, auditing API surface, or answering "what breaks if I change this?". Pairs with codebase-explorer — graph-explorer wins for symbol-precise queries, codebase-explorer wins for conceptual code-reading.
Scanned 9/4/2026
Install to Claude Code
npx -y skills add kouroshez/coding-os --skill graph-explorer --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Graph Explorer?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/kouroshez-graph-explorer-coding-os)More formats (shields.io, HTML) on the badges page.
---
name: graph-explorer
tier: exploration
domain: [universal]
description: Navigate the graph_os knowledge graph before editing load-bearing code. Use when tracing dependencies, planning a rename, auditing API surface, or answering "what breaks if I change this?". Pairs with codebase-explorer — graph-explorer wins for symbol-precise queries, codebase-explorer wins for conceptual code-reading.
last_reviewed: "2026-05-11"
---
# graph-explorer
Purpose: Load the graph_os toolset (`cos_graph_*` MCP tools) and
use it deliberately before any non-trivial code edit. The graph is the
third retrieval layer (CLAUDE.md Three-Layer Retrieval) — use it when
tree-grep or past-memory searches return noise.
Read when: Editing `src/core/**` or `src/cli/**`, producing a rename plan,
auditing API/MCP contracts, answering "what depends on X".
Skip when: You already know the blast radius, or the change is a
self-contained one-file edit with no callers.
## Decision ladder
1. **Need to know "what calls this?"** → `cos_graph_references(uid)`.
2. **Need surrounding context before editing?** → `cos_graph_context(uid_or_name, depth=1)` (Implementer pre-impl step).
3. **Planning a refactor?** → `cos_graph_impact(uid, depth=3)` (Analyst dependency map) groups edges by risk tier.
4. **Renaming a symbol?** → `cos_graph_rename_plan(uid, new_name)` before any `Edit` — returns call-sites, doc refs, tests, string literals.
5. **API / contract audit?** → `cos_graph_contracts(kinds=["http","mcp"])` (Documenter + Deployer).
6. **Tracing a fault?** → `cos_graph_trace(entry_uid)` (Debugger fault isolation step).
7. **"Is anything similar?"** → `cos_graph_similar(uid, top_k=5)`.
8. **Shortest dependency path?** → `cos_graph_path(source, target)`.
9. **Need a diagram?** → `cos_graph_export(format="mermaid", root_uid=...)`.
10. **Pre-commit self-review?** → `cos_graph_detect_changes(files=[...])` — call BEFORE `make verify`.
> **Method blast-radius — use `impact`, not bare `references(kinds="calls")`.**
> Static AST cannot resolve instance-method calls on locally-typed
> receivers (`backend.upsert_node(...)` — the type of `backend` is
> unknown), so `references(method, kinds="calls")` under-reports those
> call sites. `cos_graph_impact` compensates by traversing
> method→class→`constructs`, so "what breaks if I change this method?"
> stays complete. Treat `references(calls)` as a lower bound for methods.
> **Function blast-radius — import bindings are first-class (TASK-402).**
> Every `from M import name` site emits an `import_` node which the
> `link_import_bindings` pass binds to the real symbol (exactly-one
> match; ambiguous → skipped, never guessed). `references(function)`
> with default kinds therefore returns BOTH direct `calls` edges AND
> `imports` edges whose `import_` source node carries the caller's
> `file_path` — the init_db probe went from 6 to 80 of 106 caller files
> once this pass landed. Two caller classes stay invisible to static
> resolution and need a grep complement on security-critical sweeps:
> module-alias attribute calls (`import database as db; db.init_db()`)
> and calls embedded in string literals (`python -c "from … import …"`).
Every response carries `data.meta.layer="graph"` and `data.meta.backend`
(`sqlite` — the single store since Kùzu was retired 2026-05-18). The
`meta.backend_fallback` flag is reserved for a future graph-native
plug-in; today it is always absent/false, so you never need to treat a
result as a lower-precision fallback.
## Coverage contract — never trust a single call blindly
The biggest soundness trap in graph queries is **silent truncation**:
asking "who calls X?" on a 500-caller hub with `limit=100` (the
default) returns 100 rows and **no signal** that 400 more exist —
unless you read the coverage metadata. Every coverage-sensitive tool
exposes it; the rule below is mandatory before you act on a result.
### Signals to read on every response
| Tool | `data.total_count` | Coverage signal in meta | `data.meta.<budget>` |
|---|---|---|---|
| `cos_graph_references` | ✓ | `result_truncated` (limit hit or token-trim) · `zero_from_kind_filter` (0 rows, wrong edge kinds) | `limit` · `kinds` |
| `cos_graph_impact` | – | `walk_truncated` (BFS cap hit) | `visit_limit` · `depth` |
| `cos_graph_context` | – | `walk_truncated` (BFS cap hit) | `visit_limit` · `depth` |
| `cos_graph_path` | – | `walk_truncated` (hop saturation) | `hop_limit` |
| `cos_graph_export` | – | `result_truncated` + `max_nodes_requested` vs `max_nodes_effective` (ceiling 50k); Hub badge renders the same meta | `max_nodes` · `max_hops` |
**`result_truncated == true` or `walk_truncated == true` ⇒ the answer
is incomplete. Do NOT proceed on it.**
Why two names? `result_truncated` / `walk_truncated` flag *coverage*
truncation (a caller `limit` or BFS cap was hit); `data.meta.truncated`
flags that the envelope's *token-budget* trimmer ran (response too big,
tail rows dropped). They are separate causes, but a token-budget trim
that drops list items now ALSO sets `result_truncated` (TASK-056) — the
trimmer can silently shorten a `contracts` / `references` payload, and
the coverage check must catch that too. Net: **`result_truncated == true`
means this list is incomplete for ANY reason — re-query**; `meta.truncated`
additionally tells you the cause was the token budget.
**Truncation is not the only way to be wrong — a *zero* can be too.** With no
`kinds` argument, `references` picks defaults per node kind; ask about a kind
whose real edges are structural (`rule`, `task`, `route`, …) with the code
defaults and you get a complete query of the wrong edge types: `total_count: 0`,
`result_truncated: false`, and nothing pointing at the mistake. So the rule has a
second half: **`total_count == 0` with `meta.zero_from_kind_filter == true` ⇒ the
node HAS inbound edges and you queried past them.** `meta.edge_types_present`
names them — re-query with `kinds=` set to those. Only a zero *without* that flag
is the authoritative "nothing points here" the dead-code check depends on.
### The mandatory 2-step probe → widen workflow
```python
# 1. probe with defaults (cheap, gives you the lay of the land)
r = cos_graph_references(uid) # default limit=100
total = r["data"]["total_count"]
shown = r["data"]["count"]
# 2. if incomplete, widen with the actual total
if r["data"]["meta"]["result_truncated"]:
r = cos_graph_references(uid, limit=total) # exhaustive
# alternative: narrow the kinds filter first when total is huge
# r = cos_graph_references(uid, kinds=["calls"], limit=total)
```
For `cos_graph_impact` and `cos_graph_context`, the budget is
`visit_limit` (default 500 nodes). When `meta.walk_truncated` is true:
```python
# option A — raise the cap deliberately
r = cos_graph_impact(uid, depth=3, visit_limit=5000)
# option B — step DOWN in depth and walk each frontier separately
# (more expensive but produces tier-quality risk grouping)
r1 = cos_graph_impact(uid, depth=1)
for caller in r1["data"]["tiers"]["will_break"]:
cos_graph_impact(caller["uid"], depth=2)
```
### Per-task-class budget recipes
| Task class | Tool | Budget |
|---|---|---|
| Quick probe ("does X have any callers?") | `cos_graph_references` | `limit=20` |
| Implementation pre-check ("what neighbours?") | `cos_graph_context` | `depth=1` |
| Refactor planning ("what breaks?") | `cos_graph_impact` | `depth=3`, `visit_limit=2000` |
| Rename — must hit every site | `cos_graph_rename_plan` | (exhaustive by design) |
| Security audit — every caller chain | `cos_graph_references` then `cos_graph_impact` per caller | `limit=10_000`, `visit_limit=10_000` |
| Doc cross-reference audit | `cos_graph_references` | `kinds=["references_doc","links_to","cites_heading"]`, `limit=1000` |
**Cost math:** `cos_graph_references` is O(N) with an index; `limit=10_000`
runs in <50 ms on the highest-degree hubs in this repo. There is no
reason to under-budget a coverage-critical sweep. Pay the 50 ms.
### Anti-patterns
- Calling `cos_graph_references(uid)` once and treating the slice as
complete — without reading `total_count` or `meta.truncated`.
- Setting `limit=20` for a rename or security audit because "small is
safer" — small **hides** coverage gaps, doesn't prevent them.
- Calling `cos_graph_impact(uid, depth=4)` on a hub and not noticing
`meta.truncated` — `depth=4` × hub frontier blows past `visit_limit`
before you reach the interesting frontier.
- Asking the graph the same question twice with the same params hoping
a different answer comes back — the result is deterministic; widen
the budget or narrow the filter.
## Enforcement
- `enforce-graph-context.sh` — when editing a file matching one of the
`rag-config.yaml::graph.enforce_context_on` globs, the hook warns (or
blocks in strict mode) unless `cos_graph_context` wrote a *fresh*
`.graph/ctx-<sha>` marker this session (content-hash-bound — a consult
that went stale because the file changed no longer counts).
`enforce-skill.sh` reads the same glob list to require `graph-explorer`
on those files.
- `enforce-rename-plan.sh` — if you attempt a multi-file rename-like
Edit without a prior `cos_graph_rename_plan` in this session, the
hook warns + suggests the command.
Both hooks default to **warn** so agents discover the graph layer
instead of writing blind. Opt-out with `COS_ENFORCE_GRAPH_CONTEXT=off`
(or `=0`); promote to block with `=strict`. Same for
`COS_ENFORCE_RENAME_PLAN`.
## Auto-reindex contract
The PostToolUse hook `auto-reindex-docs.sh` re-indexes **only the file
just written** via `graph_os.tools.reindex_dispatch.dispatch(path)` —
not the whole repo. The dispatcher is incremental: it extracts that
single file's nodes / edges, upserts them into the existing graph
(idempotent on `uid`), and short-circuits via `file_index_state` when
the content hash hasn't changed. Typical cost: 20–100 ms per file,
fire-and-forget background. Use `cos graph-reindex --force` only after
a bulk shell move (`mv` / `cp` / `git checkout`) where the hook never
fired.
## Fail-loud failure modes
- MCP backend down → tools return `fail("unavailable", ...)` with
`retryable=true`. Retry after `cos graph-reindex` / server restart
— do NOT guess.
- Graph empty (fresh repo) → `_query`/`_context` return empty lists.
Run `make docs-index` / `make task-sync` / `cos graph-reindex` first.
- Confidence below 0.3 → the edge is probably a false positive.
`_impact` clusters these under the `context` tier so agents can
ignore noise.
## Web UI
For visual exploration, the unified React SPA exposes the graph at
[http://127.0.0.1:9188/graph](http://127.0.0.1:9188/graph). Start it
with `cos hub start` (FastAPI + uvicorn singleton on port 9188 that
serves every registered project). The page picks a root node, runs
depth-bounded BFS, and renders with Sigma.js + Graphology — useful
when:
- An impact/rename plan returns >10 affected files and the agent (or
user) wants to see clusters before approving.
- Walking a CONTAINS spine (Folder→File→Class→Method) is easier than
re-issuing tool calls.
- Sharing a snapshot with a human collaborator who needs to *see* the
blast radius rather than read JSON envelopes.
For one-off static export (no live server, embeddable HTML), the
legacy `cos graph-viz` command still works — kept intentionally for
sharing/embedding.
## Link-backs
- Knowledge-graph plan: [docs/phase-i-knowledge-graph-plan.md](../../../docs/phase-i-knowledge-graph-plan.md)
- MCP envelope: [docs/engineering/mcp-error-envelope.md](../../../docs/engineering/mcp-error-envelope.md)
- Rule 14 (envelope): [CLAUDE.md](../../../CLAUDE.md)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!