Skip to main content

Python bindings for UCP (Unified Content Protocol) - Rust implementation

Project description

UCP Python bindings

Python bindings for the Rust UCP implementation, including both the generic UCP graph runtime and the specialized CodeGraph API.

For agent workflows, prefer the thin Python façade exposed by ucp.query(...) and ucp.run_python_query(...).

For model/runtime integration, also see:

  • ucp.QueryLimits(...)
  • ucp.PythonQueryTool(...)
  • ucp.QueryBenchmarkCase(...) and ucp.run_query_benchmark_suite(...)

Installation

pip install ucp-content

Document usage

import ucp

doc = ucp.create("My Document")
root = doc.root_id
block = doc.add_block(root, "Hello, World!", role="paragraph")
doc.edit_block(block, "Updated content")
print(ucp.render(doc))

CodeGraph usage

import ucp

graph = ucp.CodeGraph.build("./repo")
session = graph.session()

session.seed_overview(max_depth=3)
session.expand("src/lib.rs", mode="file")

for node in graph.find_nodes(node_class="symbol", name_regex="Session|Context"):
    session.focus(node["logical_key"])
    session.apply_recommended(top=1, padding=2)

exported = session.export(compact=True, max_frontier_actions=6)
print(exported["summary"])
print(session.mutation_log()[-1]["operation"])

Agent-facing query façade

import ucp

graph = ucp.query(ucp.CodeGraph.build("./repo"))
session = graph.session()

for node in graph.find(node_class="symbol", name_regex="auth|login", limit=5):
    branch = session.fork()
    branch.add(node, detail="summary")
    branch.walk(node, mode="dependencies", depth=1, limit=8)
    if any("test" in (item.get("path") or "") for item in branch.export(compact=True)["nodes"]):
        session.add(node, detail="summary")
        session.walk(node, mode="dependencies", depth=1, limit=8)
        break

Core façade methods:

  • graph.find(...), graph.describe(...), graph.explain_selector(...), graph.path(...)
  • session.add(...), session.walk(...), session.focus(...), session.why(...)
  • session.export(...), session.explain_export_omission(...), session.why_pruned(...)
  • session.recommendations(...), session.estimate_expand(...), session.estimate_hydrate(...)
  • session.mutation_log(), session.event_log()
  • session.fork(), session.diff(...)
  • session.hydrate(...) for CodeGraph

Python query runner

run = ucp.run_python_query(
    graph,
    """
candidates = graph.find(node_class="symbol", name_regex="auth|login", limit=5)
for node in candidates:
    session.add(node, detail="summary")
    session.walk(node, mode="dependencies", depth=1)
result = session.export(compact=True)
""",
    include_export=True,
)

print(run.ok)
print(run.summary)

The runner prebinds graph, session, re, json, math, and collections so the caller can use loops, conditionals, regex, and branching without writing a graph DSL.

It also accepts bindings={...} for parameterized queries and automatically dedents normal triple-quoted snippets before execution.

For CodeGraph, exported nodes also surface convenient top-level fields like logical_key, path, and symbol_name, so Python scoring/filtering code does not have to dig through nested coderef objects.

Guarded execution

run = ucp.run_python_query(
    graph,
    "result = graph.find(node_class='symbol', name_regex='auth', limit=5)",
    limits=ucp.QueryLimits(max_seconds=2.0, max_operations=40, max_trace_events=2000),
)

QueryLimits keeps model-authored queries bounded by wall-clock time, graph/session operations, traced Python events, and stdout size.

Provider-facing tool wrapper

tool = ucp.PythonQueryTool(
    graph,
    default_include_export=True,
    default_limits=ucp.QueryLimits(max_seconds=2.0, max_operations=40),
)

openai_tool = tool.openai_tool()
result = tool.execute({"code": "result = graph.find(node_class='symbol', name_regex='auth', limit=5)"})

The wrapper also supports:

  • tool.execute_openai_tool_call(...)
  • tool.execute_anthropic_tool_use(...)

Benchmark helpers

cases = [
    ucp.QueryBenchmarkCase(
        name="rank-tests",
        description="Rank likely tests for a symbol",
        code="result = graph.find(node_class='symbol', path_regex=r'tests/.*', limit=10)",
    )
]
results = ucp.run_query_benchmark_suite(graph, cases)
summary = ucp.summarize_query_benchmark_suite(results)

Example with parameterized regexes:

run = ucp.run_python_query(
    graph,
    """
        hits = graph.find(node_class="symbol", path_regex=path_rx, name_regex=name_rx, limit=6)
        best = next(node for node in hits if "context_show" in node["logical_key"])
        session.add(best, detail="summary")
        result = session.export(compact=True)
    """,
    bindings={
        "path_rx": r"crates/ucp-cli/src/commands/(agent|codegraph)\.rs",
        "name_rx": r"context_show|get_session_mut",
    },
)

Example: rank likely tests for a symbol with plain Python heuristics:

target = graph.find(node_class="symbol", path_regex=r"crates/ucp-python/python/ucp/query\.py", name_regex=r"^run_python_query$", limit=1)[0]
tests = graph.find(node_class="symbol", path_regex=r"crates/ucp-python/tests/.*\.py", name_regex=r"test_.*query.*", limit=80)
target_words = set(re.findall(r"[A-Za-z]+", target["logical_key"].lower()))
ranked = []
for node in tests:
    words = set(re.findall(r"[A-Za-z]+", (node.get("logical_key") or "").lower()))
    score = len((target_words & words) - {"symbol", "py", "python"})
    if score:
        ranked.append((score, node["logical_key"]))
print(sorted(ranked, reverse=True)[:5])

Generic graph usage

import ucp

doc = ucp.create("Graph demo")
section = doc.add_block(doc.root_id, "Section", role="section", label="section")
note = doc.add_block(section, "Important note", role="paragraph", label="note")
helper = doc.add_code(section, "rust", "fn helper() {}", label="helper")
doc.add_edge(note, ucp.EdgeType.References, helper)

graph = ucp.Graph.from_document(doc)
sqlite = graph.persist_sqlite("graph.db", "demo")
session = sqlite.session()
session.seed_overview(max_depth=1)
session.expand("note", mode="outgoing", depth=1)
print(session.export())

Generic graph features

  • Graph.from_document(...)
  • Graph.from_json(...), Graph.load(...), Graph.save(...)
  • Graph.persist_sqlite(...), Graph.from_sqlite(...)
  • find_nodes(...), describe(...), path_between(...)
  • GraphSession with seed_overview, select, focus, expand, collapse, pin, prune, why_selected, and diff

CodeGraph features

  • CodeGraph.build(...) from a repository
  • find_nodes(...) with regex filters
  • resolve(...) and describe(...)
  • explain_selector(...) for selector provenance / ambiguity
  • path_between(...) for short graph explanations
  • CodeGraphSession for stateful exploration
  • why_selected(...) provenance/explainability with provenance chains
  • apply_recommended(...) and structured recommendations(...)
  • estimate_expand(...) / estimate_hydrate(...) for budget-aware traversal
  • mutation_log() / event_log() for observability
  • explain_export_omission(...) and why_pruned(...)
  • fork() and diff(...) for branch-and-compare workflows
  • to_json(), from_json(...), save(...), and load(...)
  • session to_json(), save(...), graph.load_session(...), and graph.load_session_json(...)

General features

  • Document operations: create, edit, move, delete blocks
  • Traversal: children, parent, ancestors, descendants, siblings
  • Finding: by tag, label, role, content type
  • Edges: create relationships between blocks
  • LLM utilities: IdMapper, PromptBuilder, prompt presets
  • Snapshots: snapshot and rollback helpers
  • UCL execution: execute UCL commands on documents

Related docs

  • docs/ucp-api/codegraph-programmatic.md
  • docs/ucp-api/python-query-tools.md
  • docs/ucp-api/graph-runtime.md
  • docs/ucp-cli/codegraph.md
  • scripts/demo_ucp_python_query.py
  • scripts/demo_codegraph_python_query.py
  • scripts/demo_codegraph_query_tool_wrapper.py
  • scripts/demo_codegraph_query_benchmarks.py
  • scripts/demo_codegraph_query_recipes.py
  • scripts/demo_codegraph_query_edge_cases.py
  • scripts/demo_codegraph_context_walk.py
  • scripts/demo_codegraph_session_observability.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ucp_content-0.1.15.tar.gz (328.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ucp_content-0.1.15-cp312-cp312-manylinux_2_34_x86_64.whl (4.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

File details

Details for the file ucp_content-0.1.15.tar.gz.

File metadata

  • Download URL: ucp_content-0.1.15.tar.gz
  • Upload date:
  • Size: 328.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ucp_content-0.1.15.tar.gz
Algorithm Hash digest
SHA256 e79a72692a6f9f05bc6883c289eefb4ce24f0b9ddd1d1f3b2b37e191d8c7186b
MD5 bee3ca4d20a9a39e095bd0eec048f1f8
BLAKE2b-256 f006bd0d35ff57342886ac4f3d781db47bf26dd282d4bc64db12fd7b2211300a

See more details on using hashes here.

File details

Details for the file ucp_content-0.1.15-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for ucp_content-0.1.15-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 8fd4882867c2b66ea81c7f70fd4751adca99a55101fab329fe48d0d82b2ab477
MD5 bb0459f45d17e2e60ee125469594a712
BLAKE2b-256 20829a6e65905f7ef59aa8bc5c008399431324f1d2cc444aebaa0a660ce60ecf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page