Docs / json-api · Edit on GitHub

rgBuilder JSON API

Programmatic reference for parsing rgBuilder output. Every structured CLI command emits one JSON document on stdout when invoked with -f json / --format json.

Canonical JSON reference (includes field catalogs formerly in cli-output-schemas.md).

Source of truth (Rust types): src/cli/*_output.rs


Table of contents

  1. Invocation
  2. Schema versioning
  3. Command index
  4. discover
  5. gql
  6. blast-radius
  7. metrics
  8. check
  9. slice
  10. inspect
  11. export (file formats)
  12. On-disk JSON after discover
  13. Exit codes
  14. Parsing recipes
  15. semantic
  16. communities
  17. cpg

1. Invocation

Global flags

FlagEffect
-f jsonEmit structured JSON on stdout
-r PATHRepository root (default: cwd)
-o FILEWrite stdout payload to a file instead of the terminal
export REPO=/path/to/coolstore
rg-build -r "$REPO" -f json gql 'MATCH (n:Function) RETURN n LIMIT 5' | jq .
rg-build -r "$REPO" -f json blast-radius ShoppingCartService -o /tmp/blast.json

Stdout vs stderr

Modestdoutstderr
-f json discoverSingle JSON telemetry objectQuiet (errors only) unless -v
-f json (other commands)Single JSON resultErrors / warnings
Default textHuman-readable tablesProgress / info logs

Rule: parse stdout only for JSON. Do not scrape stderr.

Prerequisites

All query commands require a prior successful discover (creates .rgbuilder/graph.snapshot.bin and related caches). See user-guide.md.


2. Schema versioning

Every JSON payload includes a top-level schema_version integer. Check it before parsing nested fields.

const doc = JSON.parse(stdout);
if (doc.schema_version !== 2) {
  throw new Error(`unsupported blast-radius schema ${doc.schema_version}`);
}
CommandCurrent schema_versionBreaking changes
discover2v2 introduced structured metrics block
blast-radius2v2 added target.language, target.canonical_fqn, metrics.caller_depth_limit
gql1
metrics1
check1
slice1
inspect1
semantic index2CLI index telemetry
semantic query3hits + optional expansion / fusion fields
communities1list / label
cpg (status / mutations / flows / …)1per-subcommand shapes

Omitted vs null: optional fields are absent when unset (not null), unless noted otherwise. Empty collections are usually [], not omitted.

Graph topology reuse: slice (text view) and inspect (cfg/pdg) share node/edge shapes documented in the field catalogs below (§ Field catalogs / inspect & slice).


3. Command index

Command-f jsonPrimary keysTypical use
discovermetricsCI ingestion gates, timing
gqlrows, countGraph queries, inventory
blast-radiustarget, metrics, topologyChange-impact automation
metricspagerank, betweenness, communitiesHotspot ranking
checkpassed, violationsCI policy gate
slicelines / nodes / edges / taintLine-level analysis
inspectlayer, nodes, edgesCFG/PDG/dominance dumps
semantichits / functions_indexedOpt-in NL / keyword search
communitiescommunities, modularityNamed community labels
cpgvaries by subcommandHybrid CPG façade
export❌ (file)Full-graph serialization
serveHTTP dashboard + /api/query (default); --daemon = Unix socket blast daemon

4. discover

rg-build -f json discover PATH [-l LANGS] [-e PATTERNS] [--with-cfg] [--with-taint]

TypeScript shape

interface DiscoverResponse {
  schema_version: 2;
  command: "discover";
  metrics: {
    files_discovered: number;
    files_indexed: number;
    files_skipped: number;
    nodes_generated: number;
    edges_generated: number;
    duration_ms: number;
  };
}

Example

{
  "schema_version": 2,
  "command": "discover",
  "metrics": {
    "files_discovered": 120,
    "files_indexed": 118,
    "files_skipped": 2,
    "nodes_generated": 1842,
    "edges_generated": 4103,
    "duration_ms": 12500
  }
}

jq

rg-build -f json discover . | jq '.metrics | {nodes: .nodes_generated, ms: .duration_ms}'

5. gql

rg-build -f json gql "<QUERY>" [--macro-name NAME] [--explain]

TypeScript shape

interface GqlResponse {
  schema_version: 1;
  rows: GqlRow[];       // one entry per MATCH result row
  count: number;        // always rows.length
  explain: boolean;     // mirrors --explain (plan is text-only)
}

interface GqlRow {
  binding: string;      // variable name from MATCH (e.g. "n", "a")
  node: string;         // bare symbol name (or community label)
  type: string;         // node type label, e.g. "Function" or "Community"
  file: string | null;  // source path when indexed
  community_id?: number; // present on :Community rows; optional on functions when joined
  label?: string;        // :Community label
  member_count?: number; // :Community size
}

Each rows[i] is an array of bindings (one object per variable in the RETURN clause).

Virtual :Community nodes and f.community_id filters join .rgbuilder/analysis_results.bin (see community-query-and-naming-plan.md).

Example

{
  "schema_version": 1,
  "rows": [
    [
      {
        "binding": "n",
        "node": "ShoppingCartService",
        "type": "Function",
        "file": "src/main/java/com/redhat/coolstore/service/ShoppingCartService.java"
      }
    ]
  ],
  "count": 1,
  "explain": false
}

jq

# All function names
rg-build -f json gql 'MATCH (n:Function) RETURN n' \
  | jq -r '.rows[][].node'

# Multi-binding row (a,b) from a CALLS query
rg-build -f json gql 'MATCH (a:Function)-[:CALLS]->(b:Function) RETURN a,b LIMIT 5' \
  | jq '.rows[] | map({binding, node, file})'

# Named communities
rg-build -f json gql --macro-name all_communities unused \
  | jq '.rows[:5][][] | {id: .community_id, label, member_count}'

Macros

When --macro-name is set, the positional query string is ignored:

rg-build -f json gql --macro-name all_functions 'unused'
# Macros: all_functions | direct_calls | call_chain | all_communities

6. blast-radius

rg-build -f json blast-radius SYMBOL [--depth N] [--policy-file PATH] [--with-slices]

TypeScript shape

interface BlastRadiusResponse {
  schema_version: 2;
  target: {
    id: string;              // UUID
    symbol: string;
    class_context: string | null;
    file_path: string;
    language: string;        // "java" | "rust" | "python" | "unknown"
    signature?: string;      // omitted when unknown
    canonical_fqn: string;   // prefer for routing: "Class::method"
  };
  metrics: {
    score: number;           // 0–100
    direct_callers_count: number;
    impact_zone_size: number;
    caller_depth_limit?: number;  // present when --depth N
  };
  topology: {
    scc_component_id: number | null;
    direct_callers: SymbolContext[];
    impact_zone: SymbolContext[];
  };
  gatekeeping: {
    policy_status: "SKIPPED" | "PASS" | "VIOLATED";
    violations: PolicyViolation[];
    handoffs: SliceHandoff[];  // [] unless --with-slices
  };
}

interface SymbolContext {
  id: string;       // UUID — stable join key
  fqn: string;      // display name (language-native)
  file_path: string;
}

interface SliceHandoff {
  callee: string;
  param: string;
  index: number;
}

Policy violations (gatekeeping.violations)

Tagged union — discriminant field is kind:

kindFields
domain_isolationsource_domain, reached_domain, node
scale_failurecount, max
cascade_hazardnode, betweenness, threshold
sanitization_bypasssink_line, path_trace, sanitizer_node

jq

# Impact score and caller UUIDs
rg-build -f json blast-radius ShoppingCartService \
  | jq '{score: .metrics.score, callers: [.topology.direct_callers[].id]}'

# Depth-capped impact zone
rg-build -f json blast-radius CartEndpoint --depth 3 \
  | jq '.metrics.caller_depth_limit, .topology.impact_zone | length'

# Policy gate
rg-build -f json blast-radius OrderService --policy-file policy.json \
  | jq '.gatekeeping.policy_status, .gatekeeping.violations'

Routing rule: use target.canonical_fqn and topology.*.id (UUID). Treat topology.*.fqn as display text only.

Migration from legacy flat JSON

Older rgBuilder emitted a flat object (symbol, score, direct_callers[], impact_zone[] at the root). Current output is nested with schema_version: 2. See the blast-radius field catalog in this document for the full table and jq path mapping.

# Was: jq '.score'  →  Now:
jq '.metrics.score'

# Was: jq '.direct_callers[]'  →  Now:
jq '.topology.direct_callers[].fqn'

# Prefer for automation (v2):
jq '.target.canonical_fqn'

7. metrics

rg-build -f json metrics [--pagerank] [--betweenness] [--communities] [--iterations N]

Default (no section flags) includes all three sections. Requesting a single flag omits the others entirely.

TypeScript shape

interface MetricsResponse {
  schema_version: 1;
  pagerank?: {
    top: { node: string; pagerank: number }[];  // max 20
    converged: boolean;
    iterations: number;
    max_delta: number;
  };
  betweenness?: { node: string; score: number }[];  // max 20, top-level array
  communities?: {
    count: number;
    modularity: number;
    assignments: number;
  };
}

jq

rg-build -f json metrics --pagerank | jq '.pagerank.top[:5]'
rg-build -f json metrics | jq '.communities.modularity'

8. check

rg-build -f json check --policy-file policy.json

Evaluates policy rules against git-changed functions (or all functions if git is unavailable).

TypeScript shape

interface CheckResponse {
  schema_version: 1;
  policy: string;           // path passed to --policy-file
  passed: boolean;
  violations: {
    symbol: string;
    error?: string;         // engine error (mutually exclusive with violation)
    violation?: string;     // human-readable policy text
  }[];
}

jq

rg-build -f json check --policy-file policy.json | jq '{passed, count: (.violations | length)}'

9. slice

rg-build -f json slice FILE --line N --variable VAR [--function NAME] \
  [--view text|cfg|pdg] [--direction backward|forward] [--taint]

Response shape depends on --view and --taint.

--view text (default)

interface SliceTextResponse {
  schema_version: 1;
  file: string;
  criterion: { line: number; variable: string };
  direction: "backward" | "forward";
  reduction_percent: number;
  lines: number[];              // source lines in the slice
  nodes: PdgNode[];             // PDG subgraph
  edges: PdgEdge[];
}

--view cfg

interface SliceCfgResponse {
  schema_version: 1;
  file: string;
  function: string;
  view: "cfg";
  nodes: CfgBlockNode[];
  edges: CfgEdgeNode[];
}

--view pdg

Same topology as inspect PDG (view: "pdg").

--taint

Flat summary (no graph topology):

interface SliceTaintResponse {
  schema_version: 1;
  file: string;
  function: string;
  line: number;
  variable: string;
  taint: true;
  flows: number;
  vulnerable: number;
}

Shared graph primitives

interface PdgNode {
  id: string;       // "node_0", …
  line: number;
  label: string;
  kind: string;
  defined?: string[];
  used?: string[];
}

interface PdgEdge {
  source: string;
  target: string;
  kind: "data" | "control" | string;
  variable?: string;  // data deps only
}

interface CfgBlockNode {
  id: string;       // "block_0", …
  block_index: number;
  start_line: number;
  end_line: number;
  statements: { line: number; kind: string; text: string }[];
}

interface CfgEdgeNode {
  source: string;
  target: string;
  kind: string;   // "next", "iftrue", "iffalse", …
}

jq

# Lines touched by backward slice
rg-build -f json slice src/.../Foo.java --line 42 --variable x --function Foo \
  | jq '.lines'

# Taint counts only
rg-build -f json slice src/.../Foo.java --line 10 --variable input --function Foo --taint \
  | jq '{flows, vulnerable}'

10. inspect

rg-build -f json inspect SYMBOL cfg|pdg|dom [layer options]

Requires discover --with-cfg for richest PDG/CFG data from the analysis archive.

CFG layer

interface InspectCfgResponse {
  schema_version: 1;
  symbol: string;
  layer: "cfg";
  pruned: boolean;
  nodes: CfgBlockNode[];
  edges: CfgEdgeNode[];
}

PDG layer

interface InspectPdgResponse {
  schema_version: 1;
  symbol: string;
  layer: "pdg";
  nodes: PdgNode[];
  edges: PdgEdge[];
  data_deps: number;
  control_deps: number;
}

Dominance layer

interface InspectDomResponse {
  schema_version: 1;
  symbol: string;
  layer: "dom";
  nodes: { block_index: number; start_line: number; end_line: number }[];
  idom: { block: number; immediate_dominator: number }[];
  frontiers?: { block: number; frontier_blocks: number[] }[];  // with --frontiers
}

Block references use integer block_index (sorted by start_line), not string ids.

jq

rg-build -f json inspect ShoppingCartService pdg --edge-layer data \
  | jq '{data: .data_deps, nodes: [.nodes[] | {line, label}]}'

Diagram formats: -f mermaid and -f graphviz emit diagram text (not JSON) for cfg/dom layers.


11. export (file formats)

export writes to --export-output; stdout is a one-line summary (unless global -o redirects).

rg-build export --export-format json --export-output graph.json --query all
rg-build export --export-format mermaid --export-output clearCart.mmd --query 'name:clearCart'
--export-formatFile content
jsonGraph snapshot JSON (filtered when --queryall)
graphmlGraphML XML
graphvizDOT
mermaidMermaid flowchart

--query uses filter syntax (all, name:Foo, type:Function, functions) — not GQL MATCH. The summary line reports the filtered node/edge counts.


12. On-disk JSON after discover

These files are written under .rgbuilder/ (and copied into .rgbuilder/dashboard/ for the UI). They are not emitted on stdout but are stable inputs for custom tooling.

Pathschema_versionPurpose
dashboard/manifest.json1Bundle metadata, phase flags, metric summary
dashboard/metagraph.json2Package-level graph for LOD UI
dashboard/cfg_index.json1CFG function catalog
dashboard/slice_index.json1Slice/PDG function catalog
dashboard/dataflow_index.json1Dataflow function catalog
dashboard/taint_index.json1Taint summary (discover --with-cfg)
dashboard/taint/{uuid}.json1Per-function taint flows
dashboard/slice/{uuid}.json1Per-function source + PDG bundle
dashboard/cfg/{uuid}.json1Per-function CFG preview
file_hashes.jsonIncremental discover state

manifest.json (excerpt)

{
  "schema_version": 1,
  "phases": { "0": "complete", "4": "complete", "8": "pending" },
  "graph": {
    "payload_path": "graph_payload.bin",
    "payload_format": "columnar_v2",
    "node_count": 1842,
    "edge_count": 4103
  },
  "analysis": {
    "cfg_available": true,
    "taint_available": true,
    "taint_flow_count": 12,
    "taint_vulnerable_count": 3
  },
  "metrics": {
    "function_count": 412,
    "avg_complexity": 1.2
  }
}

taint_index.json

{
  "schema_version": 1,
  "available": true,
  "detail_dir": "taint",
  "function_count": 8,
  "total_flows": 12,
  "vulnerable_flows": 3,
  "functions": [
    {
      "function_id": "uuid",
      "name": "ShoppingCartService",
      "file_path": "src/main/java/.../ShoppingCartService.java",
      "flow_count": 2,
      "vulnerable_count": 1
    }
  ]
}

taint/{uuid}.json flow entry

{
  "id": 0,
  "variable": "userInput",
  "source_type": "HttpParameter",
  "sink_type": "SqlQuery",
  "severity": 10,
  "vulnerable": true,
  "sanitizers": [],
  "source_line": 42,
  "sink_line": 88,
  "source_text": "...",
  "sink_text": "...",
  "path_lines": [42, 55, 88],
  "path_statements": ["...", "...", "..."]
}

Binary artifacts (graph.snapshot.bin, graph_payload.bin, blast_engine.snapshot.bin) use internal columnar formats — use CLI JSON or export --export-format json for portable graph access.


13. Exit codes

Command01
discoverSuccessFailure
gqlSuccessQuery/IO error
blast-radiusSuccess, or policy skipped--policy-file + policy_status == "VIOLATED" (JSON still on stdout)
checkpassed == truepassed == false
slice / inspect / metrics / exportSuccessError

CI pattern: capture stdout first, then check $?.

out=$(rg-build -f json blast-radius Foo --policy-file policy.json) || ec=$?
echo "$out" | jq .
exit "${ec:-0}"

14. Parsing recipes

Python

import json, subprocess

def rgbuilder_json(repo: str, *args: str) -> dict:
    cmd = ["rg-build", "-r", repo, "-f", "json", *args]
    out = subprocess.check_output(cmd, text=True)
    return json.loads(out)

doc = rgbuilder_json("/path/to/coolstore", "blast-radius", "CartEndpoint")
assert doc["schema_version"] == 2
for caller in doc["topology"]["direct_callers"]:
    print(caller["id"], caller["fqn"])

Node.js

import { execFileSync } from "node:child_process";

function rgbuilderJson(repo, ...args) {
  const out = execFileSync("rg-build", ["-r", repo, "-f", "json", ...args], {
    encoding: "utf8",
  });
  return JSON.parse(out);
}

const gql = rgbuilderJson(process.env.REPO, "gql", "MATCH (n:Function) RETURN n");
const names = gql.rows.flat().map((b) => b.node);

CI ingestion gate

metrics=$(rg-build -f json discover .)
nodes=$(echo "$metrics" | jq '.metrics.nodes_generated')
test "$nodes" -gt 100

Chaining discover → query

rg-build -f json discover . | tee discover.json
rg-build -f json gql --macro-name all_functions x | jq '.count'

15. semantic

Opt-in embedding index + query. Types: src/cli/semantic_output.rs.

semantic index

rg-build -r "$REPO" -f json semantic index
# offline: --embedder vocab|hash
type SemanticIndexJsonResponse = {
  schema_version: 2;
  model_id: string;
  dimensions: number;          // default 256
  functions_indexed: number;
  path: string;                // .rgbuilder/semantic_index.bin
  graph_digest?: string;
  build_stats?: {
    total: number;
    reused: number;
    embedded: number;
    removed: number;
  };
};
rg-build -r "$REPO" -f json semantic index | jq '{model_id, dimensions, functions_indexed}'

semantic query

rg-build -r "$REPO" -f json semantic query "checkout flow" --limit 10
type SemanticHitJson = {
  node_id: string;
  name: string;
  qualified_name?: string;
  file_path?: string;
  distance: number;            // Hamming
  score: number;
  fused_score?: number;
  ranking?: string;            // e.g. "fusion"
};

type SemanticQueryJsonResponse = {
  schema_version: 3;
  query: string;
  model_id: string;
  dimensions: number;
  hits: SemanticHitJson[];
  expansion?: object;          // optional query expansion payload
};
rg-build -r "$REPO" -f json semantic query "OrderService" --limit 5 \
  | jq '.hits[:5] | map({name, score, file_path})'
rg-build -r "$REPO" -f json semantic query "cart" --scope community --limit 5 \
  | jq '.hits[].name'

16. communities

List / refresh heuristic labels over label-propagation clusters. Types: src/cli/communities.rs.

rg-build -r "$REPO" -f json communities list
rg-build -r "$REPO" -f json communities label --write
type CommunitiesJsonResponse = {
  schema_version: 1;
  modularity: number;
  written: boolean;            // true after `label --write`
  communities: Array<{
    id: number;
    label: string;
    member_count: number;
  }>;
};
rg-build -r "$REPO" -f json communities list | jq '.communities[:10]'
rg-build -r "$REPO" -f json communities list | jq '{modularity, n: (.communities|length)}'

GQL alternative: --macro-name all_communities (see User Guide §6).


17. cpg

Hybrid CPG façade (needs discover --with-cfg). Types: crates/rgbuilder-analysis/src/cpg.rs + src/cli/cpg.rs. All JSON payloads use schema_version: 1.

cpg status

rg-build -r "$REPO" -f json cpg status
type CpgStatus = {
  schema_version: 1;
  archive_path: string;
  archive_present: boolean;
  function_count: number;
  graph_digest?: string;
  field_write_index_present: boolean;
  field_write_count: number;
  ast_skeleton_present: boolean;
  ast_skeleton_count: number;
};

cpg mutations

rg-build -r "$REPO" -f json cpg mutations --type ShoppingCart --exclude-ctors
type CpgMutationsResult = {
  schema_version: 1;
  type_name: string;
  exclude_ctors: boolean;
  member?: string;
  include_unresolved: boolean;
  mutations: Array<{
    file: string;
    line: number;
    code: string;
    member: string;
    function: string;
    is_constructor: boolean;
    receiver_local?: string;
    receiver_type?: string;
    kind: string;
  }>;
};

Other subcommands

SubcommandPrimary keys
cpg function <Symbol>id, name, has_l_proc, …
cpg calls <Symbol>edges[] (direction, name, id)
cpg flows …steps[] (data dependence walk)
cpg exportwrites a file (--format / --output); not stdout JSON
rg-build -r "$REPO" -f json cpg status | jq '{archive_present, function_count, field_write_count}'
rg-build -r "$REPO" -f json cpg mutations --type ShoppingCart --exclude-ctors \
  | jq '.mutations | length'
rg-build -r "$REPO" -f json cpg calls priceShoppingCart | jq '.edges[:10]'

Verification

Schema fixtures are tested in CI:

cargo test --test cli_output --test subprocess_golden_path --test all_commands_sanity

See cli-io-sanity-qe.md for the full coverage matrix.


Related

  • user-guide.md — install, ecommerce-java walkthrough (CoolStore dual API), CLI examples
  • Field catalogs — exhaustive tables later in this document (formerly cli-output-schemas.md)
  • http-api.mdrg-build serve and /api/query
  • cli-io-sanity-qe.md — subprocess JSON contract and release perf gates

Field catalogs (from former cli-output-schemas)

Conventions matrix

Conventionblast-radiusdiscovergqlmetricschecksliceinspectsemanticcommunitiescpg
schema_version✅ v2✅ v2✅ v1✅ v1✅ v1✅ v1✅ v1✅ v2/v3✅ v1✅ v1
Typed *_output.rs / analysis types
Explicit empty arrays
Omitted optional keys
Composable graph topology
Stable node UUIDs (no nil)

Tests: See cli-io-sanity-qe.md for the full coverage matrix, harness design, and extension guide.

LayerCargo targetPathCovers
1 — Unit schemacli_outputtests/cli_output/*.rsTyped *_output.rs fixtures, serde shapes
2 — Golden pathsubprocess_golden_pathtests/cli_output/subprocess_golden_path.rsDiscover + blast-radius pipelines, exit 1
3 — Full sanityall_commands_sanitytests/cli_output/all_commands_sanity.rsAll JSON commands, sandbox -d, platform rules
Fixturetests/fixtures/tiny_polyglot_repo/Java + Rust polyglot subprocess input
cargo test --test cli_output --test subprocess_golden_path --test all_commands_sanity

Source: src/cli/blast_radius_output.rsBLAST_RADIUS_SCHEMA_VERSION is 2.


1. blast-radius — schema v2

Command:

rg-build -f json blast-radius <SYMBOL> [--depth N] [--policy-file PATH] [--with-slices] [--class CLASS] [--file PATH]

Flags:

FlagDescription
--depth NCap topology.impact_zone to upstream callers within N incoming call hops (hop 1 = direct callers). Omits metrics.caller_depth_limit when unset (full closure). Score is recomputed when capped.
--policy-fileRun policy guardrails on the (possibly depth-filtered) impact zone
--with-slicesPopulate gatekeeping.handoffs (requires full graph path)
--class / --fileDisambiguate overloads

Optional warm path: rg-build serve serves the dashboard and POST /api/query on port 8080. Legacy blast socket: rg-build serve --daemon (auto-connect to .rgbuilder/query.sock unless RGBUILDER_NO_QUERY_DAEMON=1). See http-api.md.

Source: src/cli/blast_radius_output.rs
Cache enrichment: crates/rgbuilder-analysis/src/macro_call_index.rs, macro_call_lookup.rs

Top-level

{
  "schema_version": 2,
  "target": { },
  "metrics": { },
  "topology": { },
  "gatekeeping": { }
}

target — identification metadata (v2)

FieldTypeDescription
idUUID stringResolved graph node id
symbolstringBare function/method name
class_contextstring | nullContaining class or namespace when known
file_pathstringProject-relative source path (empty if unknown)
languagestring"java", "rust", "python", or "unknown"
signaturestring | omittedMethod signature when known (overload disambiguation)
canonical_fqnstringUniform Class::method (e.g. OrderService::process)
  • language comes from graph properties.language (set by language plugins at extract time) or file-extension fallback.
  • signature comes from graph Node.signature (tree-sitter during discover).
  • canonical_fqn normalizes Java dot notation to double-colon form; Rust module::fn passes through.

metrics — quantitative impact

FieldTypeDescription
scorenumberImpact score 0–100
direct_callers_countintegerImmediate caller count
impact_zone_sizeintegerTransitive caller count (functions only); reflects --depth cap when set
caller_depth_limitinteger | omittedPresent when --depth N was passed; echoes the hop cap applied to impact_zone

topology — graph layout

FieldTypeDescription
scc_component_idinteger | nullSCC index from engine; null on macro-index blast lookup cache hit
direct_callersSymbolContext[]Immediate callers
impact_zoneSymbolContext[]Transitive upstream callers (filtered by --depth when set)

SymbolContext:

{
  "id": "UUID",
  "fqn": "string",
  "file_path": "string"
}
  • fqn is language-native display text from graph qualified_name or bare name.
  • Route on target.canonical_fqn + UUIDs, not parsed topology.fqn.
  • Nil UUID policy: entries without a resolvable graph UUID are omitted from topology (never 00000000-…).
  • After discover, the blast lookup cache (macro_call_index.db / .bin) stores direct_caller_ids, impact_zone_ids, and target metadata for composable chaining.

gatekeeping — policy and slice tracing

FieldTypeDescription
policy_statusstring"SKIPPED" (default), "PASS", or "VIOLATED"
violationsarrayStructured policy violations (always present; [] when none)
handoffsarraySlice seeds (always present; [] without --with-slices)

SliceHandoff: { "callee": string, "param": string, "index": number }

PolicyViolation (internally tagged; discriminant is kind):

kindFields
domain_isolationsource_domain, reached_domain, node
scale_failurecount, max
cascade_hazardnode, betweenness, threshold
sanitization_bypasssink_line, path_trace, sanitizer_node

Schema history (migration)

Legacy flat JSON (removed) — do not parse:

{
  "symbol": "CartService",
  "score": 42.3,
  "direct_callers": ["authenticate"],
  "impact_zone": ["authenticate", "main"],
  "handoffs": []
}

v1 (nested) — replaced flat root keys with target / metrics / topology / gatekeeping. schema_version: 1.

v2 (current) — adds target.language, target.signature, target.canonical_fqn, and optional metrics.caller_depth_limit when --depth N is set. schema_version: 2.

jq path (v2)Replaces legacy
.metrics.score.score
.topology.direct_callers[].fqn.direct_callers[] (bare names)
.topology.impact_zone[].fqn.impact_zone[]
.target.id(new)
.target.canonical_fqn(new — prefer for routing)
.gatekeeping.handoffs.handoffs (always present in v1+)

FQN policy: route on target.canonical_fqn (Class::method) and topology.*.id (UUID). Treat topology.*.fqn as language-native display text only.

Cache: target metadata is written at discover into macro_call_index.db / .bin. Re-run discover after upgrading rgBuilder to populate v2 fields on cache hits.

Example (Java, cache path)

{
  "schema_version": 2,
  "target": {
    "id": "424d403b-1b2c-4a3d-8e9f-0c1b2a3f4e5d",
    "symbol": "process",
    "class_context": "OrderService",
    "file_path": "java/com/example/OrderService.java",
    "language": "java",
    "signature": "public void process(String orderId) {",
    "canonical_fqn": "OrderService::process"
  },
  "metrics": {
    "score": 25.05,
    "direct_callers_count": 1,
    "impact_zone_size": 3
  },
  "topology": {
    "scc_component_id": null,
    "direct_callers": [
      {
        "id": "8b2c4a3d-0c1b-4e5d-8e9f-424d403b1b2c",
        "fqn": "com.example.OrderController.checkout",
        "file_path": "java/com/example/OrderController.java"
      }
    ],
    "impact_zone": []
  },
  "gatekeeping": {
    "policy_status": "SKIPPED",
    "violations": [],
    "handoffs": []
  }
}

Exit codes

  • 0 — success
  • 1policy_status == "VIOLATED" when --policy-file is set (JSON still emitted to stdout first)

1b. serve — HTTP dashboard + optional socket daemon

Default (HTTP):

rg-build serve -r REPO [--open]

Binds http://127.0.0.1:8080/ — dashboard at /, GQL at POST /api/query. See http-api.md.

Legacy socket daemon (--daemon):

rg-build serve -r REPO --daemon [--socket PATH] [--idle-secs SECS]

Defaults: socket {repo}/.rgbuilder/query.sock, idle exit 300s.

Role: Loads mmap graph + blast engine once; answers NDJSON RPC (ping, blast_radius) over a Unix socket. Lite blast-radius (no --with-slices, no --policy-file) auto-connects when the socket exists.

Environment: RGBUILDER_NO_QUERY_DAEMON=1 disables client auto-connect.

Requires: prior discover producing graph.snapshot.bin and blast_engine.snapshot.bin.


2. discover — schema v2 (stdout JSON)

Command:

rg-build -f json discover PATH [--languages LANGS] [--exclude PATTERNS] [--with-security] [--with-cfg] [--with-taint] [--write-json-graph]

Source: src/cli/discover_output.rs, src/cli/discover_impl.rs

With -f json, discover suppresses progress bars and human status lines on stderr (logging quiet unless -v). Stdout receives a single telemetry object after ingestion completes. Artifacts under .rgbuilder/ are still written.

{
  "schema_version": 2,
  "command": "discover",
  "metrics": {
    "files_discovered": 10921,
    "files_indexed": 10784,
    "files_skipped": 137,
    "nodes_generated": 231410,
    "edges_generated": 562067,
    "duration_ms": 18200
  }
}
FieldSource
files_discoveredPipelineStats.files_discovered
files_indexedPipelineStats.files_processed
files_skippedPipelineStats.files_failed
nodes_generatedPipelineStats.nodes_created
edges_generatedPipelineStats.edges_created
duration_msFull discover wall-clock (includes analysis + persist)

Without -f json, discover remains human-readable text progress (unchanged).

Artifacts on disk

PathWhenFormat
.rgbuilder/graph.snapshot.binAlways (default canonical graph)Binary graph snapshot
.rgbuilder/blast_engine.snapshot.binAlwaysBinary blast engine snapshot
.rgbuilder/macro_call_index.dbAlwaysSQLite blast-radius lookup cache only (+ UUID + v2 target columns)
.rgbuilder/macro_call_index.binAlwaysBincode companion index (same data family as .db)
.rgbuilder/analysis_results.binAlwaysColumnar analysis tables
.rgbuilder/dashboard/When export succeedsStatic dashboard bundle (index.html, manifest.json, …)
.rgbuilder/graph.db / .rgbuilder/graph.json--write-json-graph onlyLegacy full graph JSON
.rgbuilder/analysis/cfg_pdg.archive.bin--with-cfg or --with-taintCFG + PDG for --with-slices
.rgbuilder/analysis/*.json--with-cfg or --with-taintPer-function analysis storage (taint, CFG, PDG)
.rgbuilder/dashboard/taint_index.json--with-cfg or --with-taintDashboard taint catalog (see json-api.md §12)

3. gql — schema v1

Command:

rg-build -f json gql "<QUERY>" [--explain] [--macro NAME]

Source: src/cli/gql_output.rs

{
  "schema_version": 1,
  "rows": [
    [
      {
        "binding": "string",
        "node": "string",
        "type": "string",
        "qualified_name": "string (optional)",
        "file": "string | null",
        "community_id": "number (optional)",
        "label": "string (optional)",
        "member_count": "number (optional)",
        "properties": "object (optional, allowlisted keys)"
      }
    ]
  ],
  "count": 0,
  "explain": false
}
FieldTypeDescription
rowsarrayOne element per result row; each row is an array of bindings
countintegerAlways equals rows.length
explainbooleanMirrors --explain flag
bindingstringVariable name from the MATCH pattern
nodestringMatched node bare name (or community label)
typestringNodeType debug name, or "Community" for virtual overlay nodes
qualified_namestring | omittedGraph FQN when present; filter with WHERE n.qualified_name = '...' (not n.name)
filestring | nullSource path when present on the node
community_idnumber | omittedCommunity id on :Community rows
labelstring | omittedHeuristic community label
member_countnumber | omittedCommunity size
propertiesobject | omittedAllowlisted extract properties (is_lambda, throws, …)

Note: The explain plan is not included in JSON; it prints to text mode only. Virtual :Community / community_id require .rgbuilder/analysis_results.bin after discover.


4. metrics — schema v1

Command:

rg-build -f json metrics [--pagerank] [--betweenness] [--communities] [--iterations N]

Source: src/cli/metrics_output.rs, src/cli/metrics.rs

Default (no section flags) computes all three sections.

{
  "schema_version": 1,
  "pagerank": {
    "top": [
      { "node": "UUID string", "pagerank": 0.0 }
    ],
    "converged": true,
    "iterations": 20,
    "max_delta": 0.0
  },
  "betweenness": [
    { "node": "UUID string", "score": 0.0 }
  ],
  "communities": {
    "count": 0,
    "modularity": 0.0,
    "assignments": 0
  }
}
SectionWhen presentNotes
pagerank--pagerank or default (all)top capped at 20 nodes
betweenness--betweenness or defaultTop-level array, top 20
communities--communities or defaultassignments = number of labeled nodes

Omitted keys: sections not requested are absent (not null, not []). Serialization uses Option + #[serde(skip_serializing_if = "Option::is_none")] via MetricsJsonResponse.


5. check — schema v1

Command:

rg-build -f json check --policy-file PATH

Source: src/cli/check_output.rs

{
  "schema_version": 1,
  "policy": "path/to/policy.json",
  "violations": [
    {
      "symbol": "string",
      "error": "string",
      "violation": "string"
    }
  ],
  "passed": true
}
FieldTypeDescription
policystringPath passed to --policy-file
violationsarrayAlways present; empty when passing
passedbooleantrue iff violations is empty

Violation entry (one of error or violation; the other is omitted):

{ "symbol": "foo", "error": "engine or policy error text" }
{ "symbol": "foo", "violation": "cascade hazard: node … betweenness …" }

Exit codes

  • 0passed == true
  • 1passed == false

6. slice — schema v1

Command:

rg-build -f json slice FILE --line N --variable VAR [--view cfg|pdg|text] [--direction backward|forward] [--taint]

Source: src/cli/slice_output.rs

CFG view (--view cfg)

{
  "schema_version": 1,
  "file": "string",
  "function": "string",
  "view": "cfg",
  "nodes": [
    {
      "id": "block_0",
      "block_index": 0,
      "start_line": 1,
      "end_line": 5,
      "statements": [
        { "line": 1, "kind": "Expression", "text": "let x = 1;" }
      ]
    }
  ],
  "edges": [
    { "source": "block_0", "target": "block_1", "kind": "next" }
  ]
}

PDG view (--view pdg)

{
  "schema_version": 1,
  "file": "string",
  "function": "string",
  "view": "pdg",
  "nodes": [
    { "id": "node_0", "line": 42, "label": "let tmp = ctx;", "kind": "Expression" }
  ],
  "edges": [
    { "source": "node_1", "target": "node_0", "kind": "data", "variable": "ctx" }
  ]
}

Text slice view (default --view text)

Includes line list and PDG subgraph topology for the slice:

{
  "schema_version": 1,
  "file": "string",
  "criterion": { "line": 42, "variable": "ctx" },
  "direction": "backward",
  "reduction_percent": 65.0,
  "lines": [40, 42],
  "nodes": [ { "id": "node_0", "line": 42, "label": "...", "kind": "..." } ],
  "edges": [ { "source": "node_1", "target": "node_0", "kind": "data", "variable": "ctx" } ]
}

Taint mode (--taint)

{
  "schema_version": 1,
  "file": "string",
  "function": "string",
  "line": 0,
  "variable": "string",
  "taint": true,
  "flows": 0,
  "vulnerable": 0
}

7. inspect — schema v1

Command:

rg-build -f json inspect SYMBOL --layer cfg|pdg|dom [layer options]

Source: src/cli/inspect_output.rs

CFG layer

{
  "schema_version": 1,
  "symbol": "string",
  "layer": "cfg",
  "pruned": false,
  "nodes": [ { "id": "block_0", "block_index": 0, "start_line": 1, "end_line": 5, "statements": [] } ],
  "edges": [ { "source": "block_0", "target": "block_1", "kind": "next" } ]
}

PDG layer

{
  "schema_version": 1,
  "symbol": "string",
  "layer": "pdg",
  "nodes": [
    { "id": "node_0", "line": 1, "label": "...", "kind": "...", "defined": ["x"], "used": ["y"] }
  ],
  "edges": [ { "source": "node_0", "target": "node_1", "kind": "control" } ],
  "data_deps": 0,
  "control_deps": 0
}

defined / used appear when --def-use is set.

Dominance layer

{
  "schema_version": 1,
  "symbol": "string",
  "layer": "dom",
  "nodes": [ { "block_index": 0, "start_line": 10, "end_line": 15 } ],
  "idom": [ { "block": 1, "immediate_dominator": 0 } ],
  "frontiers": [ { "block": 0, "frontier_blocks": [2, 3] } ]
}

Block references use stable block_index integers (sorted by start_line), not debug strings.

Other formats: --format mermaid and --format graphviz emit diagram text for CFG/dom layers (not JSON).


8. export — file output (not stdout JSON)

Command:

rg-build export --export-format json --export-output graph.json [--query "…"]

Writes to -o; stdout is a one-line summary unless output is redirected via global -o.

--formatFile content
jsonCodeGraph::export_json() (same family as graph.db)
graphmlGraphML XML
graphvizDOT
mermaidMermaid flowchart

9. semantic

See json-api.md §15 for TypeScript shapes and jq recipes.

Subcommandschema_versionSource
semantic index2SEMANTIC_INDEX_CLI_SCHEMA_VERSION
semantic query3SEMANTIC_QUERY_CLI_SCHEMA_VERSION
Field (index)TypeNotes
model_idstringEmbedder / model id
dimensionsnumberDefault 256
functions_indexednumberEntries written
pathstringIndex file path
build_statsobject?Incremental counters
Field (query hit)TypeNotes
node_idstringGraph node UUID
namestringFunction name
distancenumberHamming distance
scorenumberSimilarity or fused score
fused_scorenumber?Present when fusion ranking applied

10. communities

See json-api.md §16.

FieldTypeNotes
schema_versionnumber1
modularitynumberNewman Q
writtenboolTrue after label --write
communities[].idnumberCommunity id
communities[].labelstringHeuristic label
communities[].member_countnumberMembers

11. cpg

See json-api.md §17. Requires discover --with-cfg.

SubcommandPrimary fields
statusarchive_present, function_count, field_write_*, ast_skeleton_*
functionid, name, has_l_proc, is_constructor
callsedges[]
mutationsmutations[] (file, line, member, function, …)
flowssteps[]
exportfile output (--format / --output), not stdout JSON

All -f json CPG payloads use schema_version: 1.


Verification

# Typed schema sanity (unit fixtures per command)
cargo test --test cli_output

# Subprocess golden path (discover + blast-radius)
cargo test --test subprocess_golden_path

# Full platform I/O audit (all structured commands, sandbox -d)
cargo test --test all_commands_sanity

# Combined CI gate
cargo test --test cli_output --test subprocess_golden_path --test all_commands_sanity

Remaining gaps

  • HTML dashboard: still uses discover-time node properties, not CLI JSON shapes
  • Rust plugin: does not set properties.language on graph nodes yet (v2 falls back to .rs extension)
  • Re-run discover on repos indexed before P2 to populate blast lookup cache UUID + v2 target columns