Skip to main content
Use function metadata to find recorded callers and callees, then inspect executions that explain those relationships. This is runtime evidence for understanding code and planning a change. It does not enumerate every possible dependency. This procedure uses HTTP throughout. You need a server with recorded data, a read token, curl and Python 3 for parsing JSON. The worked example examines price_order: a checkout function that totals order lines, applies a loyalty discount and calculates tax. Use a service and function recorded by your own application, or run the optional checkout example below. Quickstart records a different, smaller operation; it does not create the price_order function used in this guide’s responses.

Record the example (optional)

Use the Python environment and running server/relay from Quickstart. Set the queue directory in this terminal, replacing the path with the relay’s absolute path:
The SDK and relay must access that same directory. The example uses fixed local data; it does not send payments or change inventory. Open the example sources and save order_service.py and test_pricing.py in the application directory containing .venv. Record the checkout with the source fingerprint supplied as a declared argument tag:
Find order-1042 in service checkout-graph-example. Confirm that its app_revision matches APP_REVISION; repeated runs can produce several matching orders. The graph contains fourteen calls, including pricing and a handled payment retry. For the HTTP workflow below, use that service and copy the exact function name from its catalog.

Locate a function

The UI’s Code tab shows the selected function’s identity and counts of observed callers and callees. It does not display source code or browse relationship lists. Use the HTTP routes below for those lists; the equivalent agent tools are linked at the end of this page. Set the server and credential explicitly. Set VEXLO_SERVICE to the service you are investigating:
List the service’s observed functions:
Inspect items in functions.json and copy the exact function name. Continue with next_cursor if the function is not on the first page. A service and full function name identify the function for detail and example requests. The optional catalog name filter is exact, not a substring search, and it is applied to the fetched page: an empty filtered page with a continuation cursor does not establish that the function was never observed. All requests inherit the token’s access scope. If it covers several teams, use team to narrow the catalog, detail and examples requests consistently; apply the same environment filter when investigating one deployment. Identically named functions can otherwise be aggregated across the accessible teams. Narrowing filters do not grant access beyond the token.

Read observed callers and callees

For the pricing function returned by the example’s catalog:
The recorded relationship fields were:
checkout is an observed caller. The observed callees are price_lines, discount_for and tax_for. The surrounding trace shows price_lines calling line_total twice, once per item, and each line calculation calling unit_price. The detail response lists direct recorded relationships, not every descendant. These are recorded-parent relationships: an uninstrumented intermediary does not create its own node or make this a complete source-level call graph. Counts and first/last-seen times describe the indexed observations, not the total number of possible paths through the application. Function observed_count counts recorded steps; error_count counts failed attempts. Use these facts to choose executions to inspect before changing an input assumption or a caller’s behavior.

Inspect real executions

Retrieve one retained example:
An example identifies trace_id, path, attempt and status, with input/output previews. Inspect examples before continuing. If it is nonempty, take the example’s trace and call:
The example belongs to the complete checkout graph, including customer lookup, inventory and payment. Reading the surrounding trace establishes where pricing ran and what consumed its result. Follow next_cursor if your trace has more call pages; the small example fits one page. The examples endpoint returns at most five examples and has no continuation cursor. Environment filters narrow retained example rows; they do not search a complete execution history for fresh examples in that environment. For broader evidence, search traces by the function and a time range, then inspect the matching recordings.

Establish the application revision

Before comparing the recording with source code, establish which application revision produced it. The example application passes APP_REVISION as an entry-point argument and includes app_revision in tag_keys, so the SDK records it as a trace tag. That is an application convention, not an automatic Vexlo field. For this single-file example, the value is a SHA-256 fingerprint of the exact application source file used for the recording. Read the tag from the selected trace:
Use the corresponding source snapshot when examining the pricing rules. In an application with many files, a deployment’s source commit or build identifier can supply your revision convention. If a recording has no revision tag, obtain provenance from deployment records before relating it to a checkout. sdk_version identifies the SDK, not the application. A stack’s file and line number alone cannot identify the application revision.

Retrieve an input and use it in a test

Retrieve the pricing call’s input and output:
For this call, both values have encoding: "json", readable value fields and truncated: false. The input contains item identifiers and quantities, not catalog prices. Inspect the two unit_price children in the same trace and retrieve their input/output values to reconstruct the prices observed for those items. Combining that mapping with the pricing input yielded this fixture and expected result:
The fixture establishes a concrete input case: a loyalty customer with two order lines totaling 3300 cents. At the identified application revision, pricing applies a 330-cent discount before calculating 238 cents of tax, producing 3208 cents. A test can preserve that order of operations rather than checking only that the price is positive. To test this case, set the catalog to the observed prices, call price_order with the recorded arguments and assert the recorded result:
For the supplied example, run the extracted test_pricing.py in the same directory as order_service.py, trace.json and values.json:
The script checks that the source fingerprint matches the trace, reads the pricing values saved above and fetches both unit_price calls using VEXLO_ENDPOINT and VEXLO_TOKEN. It requires a complete graph and one attempt per selected call, then reconstructs the catalog and runs the assertion. Missing, truncated or unavailable values stop the test instead of becoming an incomplete fixture. This test covers the recorded pricing input and the two observed catalog prices. It does not replay checkout or reproduce payment, inventory or customer service state. Reconstruct those fixtures separately when testing functions that depend on them. Use a captured input only after checking its representation and meaning. Truncation, withheld fields, type-only representations and missing external state can prevent it from becoming a valid test input. After changing code, record comparable executions at the new revision and inspect their graphs and values. Vexlo’s recordings supply evidence; they do not automatically compare revisions or prove a change correct.

Interpret missing evidence

A known function relationship can remain after all supporting trace examples expire. The function index and trace records have separate retention lifetimes. When resolving a retained example, the server skips it if its source trace or attempt no longer exists. In that case, function detail can still show an observed caller while examples is empty. An empty examples list does not invalidate an indexed relationship or establish that the function became unused. Values can also expire while a trace and its previews remain readable. Use Retention for the lifetime boundaries. Check service, team and environment scope, recording coverage, and Troubleshooting before concluding a function has no recorded usage. Even a complete retained set describes only instrumented executions that reached this server. For agent access to the same workflow, use vexlo_list_functions, vexlo_get_function, vexlo_get_function_examples, vexlo_get_trace and vexlo_get_values, documented in MCP tools.