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.16.tar.gz (329.2 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.16-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.16.tar.gz.

File metadata

  • Download URL: ucp_content-0.1.16.tar.gz
  • Upload date:
  • Size: 329.2 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.16.tar.gz
Algorithm Hash digest
SHA256 36c329c260b0808994d2f236c57c675d9802940a91223426e60afa4e20f316d4
MD5 3a543df482a658550e4d4dad10d2433e
BLAKE2b-256 29bed37578ae29a15cb46bb438be60ed886a0f2f7a90ed186f3e42ebf5adefac

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ucp_content-0.1.16-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 28d3946f61db5c18c3914618c1d7fbe0f84e2218d5ea1197e7366df2b89894f9
MD5 a1e1c8e2ec69afa1dc664ffe75afcd91
BLAKE2b-256 55ca91c1b6afdeceb0bf7e5a64107da18dd71d898903b10af7a21f897d7f072e

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