runtimeanalyz.ing ● early access · sign-up open

← All capabilities

cypher

CLI · MCP Pro

Ask anything. Arbitrary Cypher over the shared graph, for the question we didn't ship a tool for.

RenewalJob#perform EntryPoint
complete ( order Order )
CALLS
Checkout Call
Invoice.new Call
invoice Invoice
RETURNED · no rate_table ARG
invoice Object
Checkout Call
charge ( invoice Invoice )
ARG · same object
Gateway Call
The nodes and edges one query walks: an entry point, the calls it made, and the Invoice followed by object identity from the call that built it to the call that charged it.

The problem

Every tool on this site answers one question well. Sooner or later you’ll have one we didn’t think of. Say Gateway#charge started timing out last week, and you want to know which checkout paths pass it an Invoice that was built without a RateTable:

class Checkout
  def complete(order)
    invoice = order.invoice || Invoice.new(account: order.account)
    Gateway.new.charge(invoice)
  end
end

what_calls gives you the callers of charge. how_it_got_here gives you the chains that reach it. Neither joins those chains to how the argument was built, filtered to the last seven days of production, grouped by entry point. You could export the recording and write a script. Or you could ask the graph.

The fix

Every recorded call is already a node and an edge in the hosted graph. Write the question in Cypher:

MATCH (entry:EntryPoint)-[:ROOT_OF]->(:Call)-[:CALLS*]->(charge:Call {method: 'Gateway#charge'})
MATCH (charge)-[:ARG]->(invoice:Object {class: 'Invoice'})
MATCH (built:Call {method: 'Invoice.new'})-[:RETURNED]->(invoice)
WHERE charge.deployed_at > datetime() - duration('P7D')
  AND NOT (built)-[:ARG {name: 'rate_table'}]->()
RETURN entry.identity AS entry_point, count(*) AS calls
ORDER BY calls DESC
$ ra cypher -f slow_charges.cypher

entry_point                          calls
POST /checkout (CheckoutsController)  1,904
RenewalJob#perform                      212

Two entry points build an Invoice without a rate table, and the renewal job is new this week. That’s the one to fix:

class RenewalJob
  def perform(subscription)
    invoice = Invoice.new(account: subscription.account, rate_table: RateTable.for(subscription.account))
    Checkout.new.complete(subscription.order_with(invoice))
  end
end

Your agent can do the same over MCP: it writes the query, runs it, and reads the rows back.

How it works

The hosted graph is a Neo4j database that every recorded deploy writes into. The schema is small:

  • Call nodes, one per recorded call, with the method, the file and line, and the deploy.
  • CALLS edges from a call to the calls it made, in order, with counts on the rolled-up edges.
  • Object nodes for the receivers, arguments and return values, labelled by class, joined by object identity so a value can be followed from the call that built it to every call it reached.
  • EntryPoint nodes for the spec example, request or job that started each call tree.

That’s the same structure every other tool queries. cypher hands you the query language directly, read-only, over the pooled graph for your whole app.

Limits

  • Classes and names, never values. The graph stores class names, method names and object identity. You can ask which class an argument was; you can’t ask what it contained.
  • Read-only. Queries can’t change the graph.
  • It’s a real query language. A query that walks every path in a busy app will be slow. Queries run with a time limit, and anything you run often is a candidate for a tool of its own.

coupling_map

CLI · MCP Pro

Coupling from real load. Module and namespace coupling drawn from real production calls. Which parts of your app actually talk, and how much.

See more →

what_calls

CLI · LSP · MCP free

Who can call this method. Every caller of a method from real runs, with where and how often. The calls that actually happened, not grep. what_it_calls does the reverse.

See more →

where_nil_comes_from

CLI · MCP free

Where nil shows up. The methods that returned nil and the arguments that received it at runtime, logged as NilClass and tied to the errors that followed. The case a declared type quietly hides.

See more →