

<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Notebook symbol graph

Statically match notebook definitions and calls so agents can see which
cells define, call, and depend on a symbol.

This notebook adds a static map across notebooks. It does not execute
project code; it parses cells with `ast`, records where symbols are
defined, and reports which cells call those symbols.

That gives agents a fast way to answer questions like “where is this
helper used?” before editing a private function or moving code between
notebooks.

The graph is a navigation aid, not a runtime dependency analyzer. It
answers practical maintenance questions: where is this symbol defined,
who calls it, what does it call, can one symbol reach another through
static calls, and are any notebooks importing private helpers that
should stay local?

``` python
symbol_graph(path="nbs", symbol="write_nb")
symbol_connection(path="nbs", start="symbol_connection", end="_resolve_callees")
private_symbol_report(path="nbs")
```

#### Production contract

The graph tools are maintenance aids, not runtime dependency analyzers.
Production behavior is limited to static definitions, callers, callee
summaries, order warnings, and private-boundary reports with modest
claims about accuracy.

## 1. Parse notebooks and collect evidence

The first chapter turns notebook cells into small, inspectable records.
Each helper has one job so the order of the parser is visible to the
reader.

#### Discovering definitions and calls

The parser records function, class, and method definitions, then walks
call expressions inside each parsed tree. Both fully qualified names and
short names are kept because notebooks often import helpers into local
scope.

#### Building graph records

Each code cell can contribute definition records and caller records. The
collected graph is deliberately simple dictionaries so reports, tests,
and future tools can inspect it without a graph database.

#### Cell order warnings

Notebook cells are executed in order, so a top-level call should not
appear before the cell that defines or imports its callable. The order
checker also looks inside function bodies for callable roots that are
never defined or imported, which catches rarely exercised missing
imports before runtime.

The checker treats names bound inside ordinary blocks as local to the
cell. That matters for context-manager examples such as
`with write_demo_notebook(...) as path:` and capture helpers such as
`out = StringIO()`: those variables are setup, not missing imports.

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L275"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_FunctionDef

``` python
def visit_FunctionDef(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L283"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_AsyncFunctionDef

``` python
def visit_AsyncFunctionDef(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L288"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_Lambda

``` python
def visit_Lambda(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L309"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_ListComp

``` python
def visit_ListComp(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L314"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_SetComp

``` python
def visit_SetComp(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L319"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_DictComp

``` python
def visit_DictComp(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L324"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_GeneratorExp

``` python
def visit_GeneratorExp(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L329"
target="_blank" style="float:right; font-size:smaller">source</a>

### \_CallRootVisitor.visit_Call

``` python
def visit_Call(
    node
):
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L387"
target="_blank" style="float:right; font-size:smaller">source</a>

### notebook_order_problems

``` python
def notebook_order_problems(
    path:str='nbs', nb:NoneType=None
):
```

*Return structured calls-before-definitions and missing callable import
warnings.*

#### Editing without committing

[`notebook_order_problems`](https://MorsCerta-crypto.github.io/nbskill/graph.html#notebook_order_problems)
accepts an in-memory notebook so edit tools can warn about a call that
now precedes its definition before they commit the change.

``` python
order_problems = notebook_order_problems("nbs/10_graph.ipynb")
assert isinstance(order_problems, list)
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L423"
target="_blank" style="float:right; font-size:smaller">source</a>

### notebook_order_problem_lines

``` python
def notebook_order_problem_lines(
    path:str='nbs'
):
```

*Return style-check lines for calls before definitions/imports and
missing callable imports.*

## 2. Resolve and report relationships

The graph is approximate by design. Matching by exact or short symbol
name is enough to surface likely callers and callees, which is the
useful pre-edit signal for this project.

A symbol connection follows definition-to-callee edges with a bounded
breadth-first search. That keeps the answer practical: show the shortest
static call chain that explains how one symbol can reach another, and
stop before approximate short-name matching turns into noise.

#### Formatting reports

The reporting helpers turn graph records into compact text for humans
and complete structured data for automation. Text output stays short
enough for agent context, while JSON output keeps every caller usage
line so migration scripts do not have to scrape truncated prose.

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L554"
target="_blank" style="float:right; font-size:smaller">source</a>

### symbol_graph_data

``` python
def symbol_graph_data(
    path, symbol
):
```

*Return structured definitions, callers, and callees for a symbol.*

#### Symbols as graph entities

A symbol becomes more useful when its caller and callee relationships
travel with it. The graph layer patches those relationship methods onto
[`NotebookSymbol`](https://MorsCerta-crypto.github.io/nbskill/foundation.html#notebooksymbol)
because this notebook owns the static call graph.

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L579"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotebookSymbol.definitions

``` python
def definitions():
```

*Return definition records for this symbol.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L585"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotebookSymbol.callers

``` python
def callers():
```

*Return call records that reference this symbol.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L591"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotebookSymbol.caller_usages

``` python
def caller_usages():
```

*Return formatted caller usage snippets for this symbol.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L597"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotebookSymbol.callees

``` python
def callees():
```

*Return symbols called by this symbol.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L603"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotebookSymbol.relationships_to_record

``` python
def relationships_to_record():
```

*Return this symbol with caller and callee relationship data.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L609"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotebookSymbol.relationships_to_xml

``` python
def relationships_to_xml():
```

*Return an XML-shaped symbol relationship view for LLM context.*

``` python
_graph_example_data = {
    "symbol": "helper",
    "definitions": [{"symbol": "helper", "path": "demo.ipynb", "cell_id": "abc", "cell_idx": 1, "module": "demo", "kind": "function"}],
    "callers": [{"path": "demo.ipynb", "cell_id": "def", "cell_idx": 2, "calls": ["helper"]}],
    "caller_usages": [{"path": "demo.ipynb", "cell_id": "def", "lineno": 1, "line": "helper()"}],
    "callees": ["leaf"],
    "graph": {"definitions": []},
}
_graph_example = NotebookSymbol.from_graph_data(_graph_example_data)
{
    "definitions": _graph_example.definitions(),
    "callers": _graph_example.callers(),
    "caller_usages": _graph_example.caller_usages(),
    "callees": _graph_example.callees(),
}
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L626"
target="_blank" style="float:right; font-size:smaller">source</a>

### symbol_graph_public_data

``` python
def symbol_graph_public_data(
    data
):
```

*Return the compact public view of symbol graph data.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L661"
target="_blank" style="float:right; font-size:smaller">source</a>

### symbol_usage_summary

``` python
def symbol_usage_summary(
    path, symbols
):
```

*Return a compact caller/callee summary for one or more symbols.*

#### Public graph reports

[`symbol_graph`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_graph)
focuses on one symbol’s definitions, callers, caller usage lines, and
callees.
[`symbol_connection`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_connection)
answers the next question: whether one symbol can reach another by
following static callee edges, returning the shortest chain it finds.
Default output is compact text for quick orientation; `json_output=True`
returns structured data for programmatic refactors.
[`private_symbol_report`](https://MorsCerta-crypto.github.io/nbskill/graph.html#private_symbol_report)
looks for cross-notebook calls to private helpers, which is useful when
deciding whether a private function can be changed safely.

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L704"
target="_blank" style="float:right; font-size:smaller">source</a>

### symbol_graph

``` python
def symbol_graph(
    path:str='nbs', # Notebook file, directory, or glob to scan
    symbol:str='', # Function, class, or Class.method to inspect
    json_output:bool=False, # Print complete structured JSON instead of compact text
):
```

*Print definitions, callers, and callees for a notebook symbol.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L722"
target="_blank" style="float:right; font-size:smaller">source</a>

### private_symbol_report

``` python
def private_symbol_report(
    path:str='nbs', # Notebook file, directory, or glob to scan
):
```

*Print cross-notebook calls to imported private `_` symbols.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L747"
target="_blank" style="float:right; font-size:smaller">source</a>

### symbol_connection

``` python
def symbol_connection(
    path:str='nbs', # Notebook file, directory, or glob to scan
    start:str='', # Symbol where traversal starts
    end:str='', # Symbol to find by following callees
    max_depth:int=6, # Maximum number of edges to follow
    json_output:bool=False, # Print complete structured JSON instead of compact text
):
```

*Print the shortest static callee chain connecting two notebook
symbols.*

``` python
root = demo_path("10_graph_example")
try:
    root.mkdir()
    write_nb(new_nb([
        mk_cell("#| default_exp demo"),
        mk_cell("#| export\ndef helper():\n    return 1\n\ndef target():\n    return helper()"),
        mk_cell("target()"),
    ]), root / "demo.ipynb")
    _example_symbol_graph(str(root), "helper")
finally:
    remove_demo_path(root)
```

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L867"
target="_blank" style="float:right; font-size:smaller">source</a>

### symbol_catalog

``` python
def symbol_catalog(
    path:str='nbs'
):
```

*Return notebook symbols with placement and reuse evidence.*

## 3. Build a notebook knowledge graph

[`notebook_knowledge_graph_data`](https://MorsCerta-crypto.github.io/nbskill/graph.html#notebook_knowledge_graph_data)
exports a typed, deterministic graph for local notebook structure. Edges
carry confidence and evidence so call/import facts stay separate from
heuristic similarity links.

## Definition order for the knowledge graph

The notebook executes from top to bottom. The catalog builder and its
helpers therefore appear before the knowledge-graph builder, which calls
[`symbol_catalog`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_catalog).

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L1199"
target="_blank" style="float:right; font-size:smaller">source</a>

### notebook_knowledge_graph_data

``` python
def notebook_knowledge_graph_data(
    path:str='nbs'
):
```

*Return a typed graph of notebook, cell, symbol, import, and heading
structure.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L1220"
target="_blank" style="float:right; font-size:smaller">source</a>

### notebook_knowledge_graph

``` python
def notebook_knowledge_graph(
    path:str='nbs', json_output:bool=False
):
```

*Print a typed notebook knowledge graph summary, or JSON when
requested.*

## 4. Offer conservative reuse advice

The advisor turns graph evidence into conservative suggestions. It never
moves code; it records why an existing symbol or notebook is worth
inspecting before an agent writes another helper.

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L1330"
target="_blank" style="float:right; font-size:smaller">source</a>

### reuse_advice

``` python
def reuse_advice(
    goal, path:str='nbs', source:NoneType=None, top_k:int=5
):
```

*Return existing symbols and notebooks to inspect before implementing
code.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L1430"
target="_blank" style="float:right; font-size:smaller">source</a>

### placement_advice

``` python
def placement_advice(
    path:str='nbs', symbol:NoneType=None, source:NoneType=None, notebook:NoneType=None, top_k:int=5
):
```

*Return ranked notebook candidates plus evidence for a symbol or source
snippet.*

------------------------------------------------------------------------

<a
href="https://github.com/MorsCerta-crypto/nbskill/blob/main/nbskill/graph.py#L1528"
target="_blank" style="float:right; font-size:smaller">source</a>

### notebook_advice_problems

``` python
def notebook_advice_problems(
    path:str='nbs'
):
```

*Return reuse and placement advisory diagnostics for notebook style
reports.*

``` python
def _write_graph_test_notebooks(root):
    root.mkdir()
    lib = root / "lib.ipynb"
    caller = root / "caller.ipynb"
    write_nb(new_nb([
        mk_cell("#| default_exp lib"),
        mk_cell("#| export\ndef helper():\n    return 1\n\ndef _secret():\n    return helper()\n\ndef target():\n    return helper()"),
    ]), lib)
    write_nb(new_nb([mk_cell("from nbskill.lib import target, _secret\nvalue = target()\n_secret()")]), caller)
    return lib, caller
```

## 5. Explore the graph

The symbol graph can answer questions that plain text search only
approximates. It can connect a definition to the cells that call it,
show what that definition itself calls, rank symbols by likely edit
blast radius, and expose private helpers that have crossed notebook
boundaries.

These prototype cells stay non-exported on purpose. They test strategies
over the current `nbs` graph before deciding whether any report deserves
a public Python API. The results are static-analysis hints, not deletion
permission: dynamic imports, entry points, examples, and short-name
collisions still need human review.

``` python
def _explore_definition_id(record): return (record.get("module"), record["symbol"], record["path"], record["cell_id"])
```

``` python
def _explore_call_sites_by_name(graph):
    sites = defaultdict(list)
    for caller in graph["callers"]:
        for site in caller.get("call_sites", ()):
            sites[site.get("name")].append(dict(path=caller["path"], cell_id=caller["cell_id"], cell_idx=caller["cell_idx"], lineno=site.get("lineno"), line=site.get("line")))
    return sites
```

``` python
def _explore_unique_sites(rows):
    seen, unique = set(), []
    for row in rows:
        key = (row["path"], row["cell_id"], row.get("lineno"), row.get("line"))
        if key in seen: continue
        seen.add(key)
        unique.append(row)
    return unique
```

``` python
def _explore_callers_by_definition(graph):
    sites = _explore_call_sites_by_name(graph)
    callers = {}
    for record in graph["definitions"]:
        names = dict.fromkeys([record["symbol"], symbol_short_name(record["symbol"])])
        rows = [site for name in names for site in sites.get(name, ())]
        callers[_explore_definition_id(record)] = _explore_unique_sites(rows)
    return callers
```

``` python
def _explore_unused_candidates(graph):
    callers = _explore_callers_by_definition(graph)
    result = {"public": [], "private": []}
    for record in graph["definitions"]:
        if callers[_explore_definition_id(record)]: continue
        visibility = "private" if record["symbol"].startswith("_") else "public"
        result[visibility].append(dict(symbol=record["symbol"], kind=record["kind"], module=record.get("module"), path=record["path"], cell_id=record["cell_id"], caveat="check Python callers, docs, and dynamic calls before deleting"))
    for rows in result.values(): rows.sort(key=lambda row: (row["module"] or "", row["symbol"]))
    return result
```

``` python
def _explore_hotspots(graph):
    callers = _explore_callers_by_definition(graph)
    rows = []
    for record in graph["definitions"]:
        fan_in = len({(site["path"], site["cell_id"]) for site in callers[_explore_definition_id(record)]})
        fan_out = len([symbol for symbol in _resolve_callees(graph, record.get("calls", ())) if symbol != record["symbol"]])
        if fan_in or fan_out:
            rows.append(dict(symbol=record["symbol"], module=record.get("module"), path=record["path"], cell_id=record["cell_id"], fan_in=fan_in, fan_out=fan_out, score=fan_in * 2 + fan_out))
    return sorted(rows, key=lambda row: (row["score"], row["fan_in"], row["fan_out"]), reverse=True)
```

``` python
def _explore_private_boundary_leaks(graph):
    definitions = {(row.get("module"), row["symbol"]): row for row in graph["definitions"]}
    rows = []
    for imported in graph["imports"]:
        if not symbol_short_name(imported["symbol"]).startswith("_"): continue
        definition = definitions.get((imported["module"], imported["symbol"]))
        if not definition or definition["path"] == imported["path"]: continue
        for caller in graph["callers"]:
            if caller["path"] != imported["path"]: continue
            sites = [site for site in caller.get("call_sites", ()) if _call_matches_symbol(site.get("name"), imported["local"])]
            if sites:
                row = dict(symbol=imported["symbol"], local=imported["local"], defined_path=definition["path"])
                row.update(defined_cell=definition["cell_id"], called_path=caller["path"], called_cell=caller["cell_id"], line=sites[0].get("line"))
                rows.append(row)
    return rows
```

``` python
def _explore_ambiguous_short_names(graph):
    sites = _explore_call_sites_by_name(graph)
    by_short = defaultdict(list)
    for record in graph["definitions"]: by_short[symbol_short_name(record["symbol"])].append(record)
    rows = []
    for name, records in by_short.items():
        locations = {(row.get("module"), row["symbol"], row["path"], row["cell_id"]) for row in records}
        if len(locations) <= 1: continue
        row = dict(short_name=name, definition_count=len(locations), call_site_count=len(sites.get(name, ())))
        row.update(symbols=sorted({row["symbol"] for row in records})[:6], caveat="short-name matching can overconnect this symbol")
        rows.append(row)
    return sorted(rows, key=lambda row: (row["call_site_count"], row["definition_count"]), reverse=True)
```

``` python
def _explore_notebook_hotspots(graph, hotspots, private_leaks, order_problems=(), style=None):
    def_counts = Counter(row["path"] for row in graph["definitions"])
    central = Counter(row["path"] for row in hotspots[:30])
    leaks = Counter(row["called_path"] for row in private_leaks)
    order = Counter(row["path"] for row in order_problems)
    style_rows = (style or {}).get("notebook_problems", ())
    style_counts = Counter(row["path"] for row in style_rows)
    rows = []
    for path in set(def_counts) | set(central) | set(leaks) | set(order) | set(style_counts):
        score = central[path] * 3 + leaks[path] * 2 + order[path] + style_counts[path]
        row = dict(path=path, definitions=def_counts[path], central_symbols=central[path])
        row.update(private_leaks=leaks[path], order_warnings=order[path], style_warnings=style_counts[path], score=score)
        rows.append(row)
    return sorted(rows, key=lambda row: (row["score"], row["definitions"]), reverse=True)
```

The first useful reports are comparative rather than absolute. A symbol
with no resolved callers is a cleanup candidate, not proof of dead code.
A high fan-in or fan-out symbol deserves more careful tests before
editing. A private boundary leak shows where notebook-local code has
become a cross-module dependency. Ambiguous short names show where the
current graph can lie by matching `Class.method` and `method` too
generously.

``` python
_explore_scope = "nbs/*.ipynb"
_explore_notebook = notebook_paths("nbs/10_graph.ipynb")[0]
_explore_graph = _collect_graph(_explore_scope)
_explore_style = style_report(_explore_notebook)
_explore_unused = _explore_unused_candidates(_explore_graph)
_explore_hotspot_rows = _explore_hotspots(_explore_graph)
_explore_private_leaks = _explore_private_boundary_leaks(_explore_graph)
_explore_ambiguous = _explore_ambiguous_short_names(_explore_graph)
_explore_notebooks = _explore_notebook_hotspots(_explore_graph, _explore_hotspot_rows, _explore_private_leaks, notebook_order_problems(_explore_scope), _explore_style)
_explore_connection_pairs = [
    ("symbol_connection", "_resolve_callees"),
    ("symbol_graph", "_caller_usage_records"),
    ("style_check", "notebook_order_problem_lines"),
]
_explore_connections = [
    _symbol_connection_public_data(_symbol_connection_data(_explore_scope, start, end, max_depth=6))
    for start, end in _explore_connection_pairs
]

print(f"graph: {len(_explore_graph['definitions'])} definitions, {len(_explore_graph['callers'])} caller cells, {len(_explore_graph['imports'])} imports")
print("hotspots:", ", ".join(row["symbol"] for row in _explore_hotspot_rows[:8]))
print("private leaks:", ", ".join(row["symbol"] for row in _explore_private_leaks[:6]))
print("unused public candidates:", ", ".join(row["symbol"] for row in _explore_unused["public"][:6]))
print("ambiguous names:", ", ".join(row["short_name"] for row in _explore_ambiguous[:6]))
print("notebook hotspots:", ", ".join(row["path"] for row in _explore_notebooks[:4]))
for row in _explore_connections:
    chain = " -> ".join(row["symbols"]) if row["found"] else "not found"
    print(f"connection {row['start']} to {row['end']}: {chain}")
```

#### Public behavior

The order checker exposes calls that appear before their definitions or
imports, which makes notebook execution problems visible before runtime.

``` python
_order_examples = notebook_order_problems("nbs/10_graph.ipynb")
print(f"order diagnostics: {len(_order_examples)}")
```

#### notebook_order_problem_lines

[`notebook_order_problem_lines`](https://MorsCerta-crypto.github.io/nbskill/graph.html#notebook_order_problem_lines)
converts the structured warnings into concise style-check lines that are
easy to print or filter.

``` python
_order_lines_example = notebook_order_problem_lines("nbs/10_graph.ipynb")
print("\n".join(_order_lines_example[:3]) or "no order warnings")
```

#### symbol_graph_data

[`symbol_graph_data`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_graph_data)
is the structured entry point for callers that need definitions, caller
sites, and callee information without parsing report text.

``` python
_graph_data_example = symbol_graph_data("nbs/10_graph.ipynb", "symbol_graph")
print(dict(symbol=_graph_data_example["symbol"], definitions=len(_graph_data_example["definitions"]), callers=len(_graph_data_example["callers"])))
```

#### symbol_graph_public_data

[`symbol_graph_public_data`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_graph_public_data)
keeps the automation-facing shape small while preserving caller usage
records.

``` python
_public_graph_example = symbol_graph_public_data(_graph_data_example)
print(dict(symbol=_public_graph_example["symbol"], callers=len(_public_graph_example["callers"]), usages=len(_public_graph_example["caller_usages"])))
```

#### symbol_usage_summary

[`symbol_usage_summary`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_usage_summary)
is the compact human-facing view for checking several symbols at once.

``` python
_usage_summary_example = symbol_usage_summary("nbs/10_graph.ipynb", ["symbol_graph", "symbol_connection"])
print(_usage_summary_example.splitlines()[0])
```

#### Public behavior

The report function prints a short orientation view for a symbol; use
the data functions above when a caller needs machine-readable details.

``` python
symbol_graph(path="nbs/10_graph.ipynb", symbol="symbol_graph")
```

#### private_symbol_report

[`private_symbol_report`](https://MorsCerta-crypto.github.io/nbskill/graph.html#private_symbol_report)
is a boundary check for private helpers imported across notebooks.

``` python
private_symbol_report(path="nbs/10_graph.ipynb")
```

#### symbol_connection

[`symbol_connection`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_connection)
follows the shortest approximate call chain between two symbols and
prints whether a connection was found.

``` python
symbol_connection(path="nbs/10_graph.ipynb", start="symbol_graph", end="_collect_graph")
```

#### notebook_knowledge_graph_data

[`notebook_knowledge_graph_data`](https://MorsCerta-crypto.github.io/nbskill/graph.html#notebook_knowledge_graph_data)
returns a typed graph of notebook, cell, symbol, import, and heading
nodes.

``` python
_knowledge_graph_example = notebook_knowledge_graph_data("nbs/10_graph.ipynb")
print(dict(nodes=len(_knowledge_graph_example["nodes"]), edges=len(_knowledge_graph_example["edges"]), issues=len(_knowledge_graph_example["issues"])))
```

#### notebook_knowledge_graph

[`notebook_knowledge_graph`](https://MorsCerta-crypto.github.io/nbskill/graph.html#notebook_knowledge_graph)
renders the typed graph as a concise summary for quick inspection.

``` python
notebook_knowledge_graph(path="nbs/10_graph.ipynb")
```

#### symbol_catalog

[`symbol_catalog`](https://MorsCerta-crypto.github.io/nbskill/graph.html#symbol_catalog)
records where symbols live and the text evidence that helps agents
decide what to reuse.

``` python
_catalog_example = symbol_catalog("nbs/10_graph.ipynb")
print(f"catalog symbols: {len(_catalog_example['symbols'])}")
```

#### reuse_advice

[`reuse_advice`](https://MorsCerta-crypto.github.io/nbskill/graph.html#reuse_advice)
ranks existing symbols and notebooks before new code is written.

``` python
_reuse_example = reuse_advice("notebook graph parser", path="nbs/10_graph.ipynb", top_k=3)
print(f"reuse matches: {len(_reuse_example['matches'])}")
```

#### placement_advice

[`placement_advice`](https://MorsCerta-crypto.github.io/nbskill/graph.html#placement_advice)
ranks likely notebook locations for a symbol or source snippet.

``` python
_placement_example = placement_advice(path="nbs/10_graph.ipynb", symbol="symbol_graph", top_k=3)
print(f"placement candidates: {len(_placement_example['candidates'])}")
```

#### notebook_advice_problems

[`notebook_advice_problems`](https://MorsCerta-crypto.github.io/nbskill/graph.html#notebook_advice_problems)
collects conservative reuse, placement, and private-boundary diagnostics
for style reports.

``` python
_advice_problems_example = notebook_advice_problems("nbs/10_graph.ipynb")
print(f"advice diagnostics: {len(_advice_problems_example)}")
```
