3.1

inspect-artifact

inspect-artifact reads the file as a container, hashes it, names its format, and returns one Evidence record that tells you which tool to run next.

You built ledger-arm64-O1 from ledger.c and ledger-main.c with clang. An agent is about to analyze it, and you want the first call to be cheap, offline, and honest about what it did not do. inspect-artifact is that call. It needs no Ghidra, it returns in about a second, and its record ends with the name of the next tool.

When you finish this section, you can run inspect-artifact on a file you built and read its manifest and its one occurrence. You can also say why the record names open_binary as the next probe.

One command, one record

the command and its exittextFull log
$ rea inspect-artifact fixtures/ledger-arm64-O1 --format json
[exit 0] (…) -> 03-inspect-artifact.json
Two lines from the command index. The time in parentheses changes on every run and is cut.

The record comes from the provider rea-artifact-graph, named "REA safe artifact graph provider", version 1. No analysis engine runs. The tool opens the file, hashes it, names the format from the header, and builds an inventory of the file as a container.

Artifact graph: the inventory rea builds of one file and the files inside it. A node is one distinct content, identified by its SHA-256. An occurrence is one place where that content appears, with a logical path. An edge joins a container to a member.

the head of the recordjsonFull log
{
  "evidence_id": "ev_0e878985…",
  "subject": {
    "name": "ledger-arm64-O1",
    "digest": {
      "sha256": "01b5d08b…"
    },
    "local_path": "$CAPTURE/fixtures/ledger-arm64-O1",
    "format": "mach-o",
    "architecture": null
  },
  "provider": {
    "id": "rea-artifact-graph",
    "name": "REA safe artifact graph provider",
    "version": "1"
  },
  …
  "operation": "inspect_artifact",
  "parameters": {
    "integrity_policy": "fail"
  },
  …
}
The substeps array and everything after it are cut. The capture kit masks local_path.

The SHA-256 is the one 00-fixtures.txt lists for the file, and every later record about this file carries the same digest. The format is mach-o, read from the magic bytes. The architecture is null. This provider does not read cputype, and the next section shows the tool that does. The one parameter is integrity_policy, set to fail.

The manifest and the occurrence

The record has one substep, inventory_artifact, with status: "completed" and its own Evidence record nested inside. Its manifest counts the graph.

the manifest, the node, and the occurrencejsonFull log
"manifest": {
  "manifest_id": "agm_8e2e5c4c…",
  …
  "graph_sha256": "b6c8ab6f…",
  "node_count": 1,
  "occurrence_count": 1,
  "edge_count": 0
},
"nodes": [
  {
    "artifact_id": "art_8906b5a7…",
    "format": "mach-o",
    "sha256": "01b5d08b…",
    "size": 33872,
    …
    "content_state": "materialized",
    "limitations": []
  }
],
"occurrences": [
  {
    "occurrence_id": "occ_35a9bb48…",
    …
    "logical_path": ".",
    "entry_kind": "file",
    "artifact_kind": "executable",
    "artifact_format": "mach-o",
    "declared_size": 33872,
    …
    "executable": true,
    "encrypted": false,
    "hash_status": "verified",
    …
  }
],
Cut from the inventory substep to the manifest counts, the one node, and the one occurrence.

One node, one occurrence, no edges. The executable is its own container and has no members. The limitation "Artifact has no child container entries." says the same in words. The node reports size: 33872, the byte count in 00-fixtures.txt, and content_state: "materialized". The occurrence has logical_path: ".", the root, and artifact_kind: "executable". For an .asar or a .zip, this is where every member file would appear with its own node and path.

Branches and the next probe

what the inspection did not dojsonFull log
"unexplored_branches": [
  {
    "branch_id": "aib_ff20889e…",
    "reason": "format-specific-analysis-required",
    "detail": "open_binary was not run by provider-neutral artifact inspection.",
    "next_probe": {
      "operation": "open_binary",
      "rationale": "Bind one deep native provider before function-level analysis.",
      "authority": "native-analysis-provider"
    },
    …
  }
],
…
"confidence": "observed",
"authority": "shipped-artifact",
"environment": null,
"limitations": [
  "Artifact has no child container entries.",
  "Inspection derives bounded static hypotheses and next probes; it does not execute the artifact or claim format-specific semantics."
],
The hypotheses and contradictions arrays are empty and are cut with the coverage block.

rea builds one unexplored branch for every next probe it lists, with the reason format-specific-analysis-required. The second limitation is a constant in the same file. The record is observed with authority shipped-artifact: rea read the bytes of the file you gave it and derived nothing from another record. The coverage block reports complete-within-substeps with one substep, one observation, one branch, one probe, and nothing omitted.

Fig. 3.1the inspect-artifact record for ledger-arm64-O1tree
The inspect-artifact record for ledger-arm64-O1 One Evidence record from the rea-artifact-graph provider. Its subject is ledger-arm64-O1, a 33872-byte Mach-O whose SHA-256 starts 01b5d08b. One substep, inventory_artifact, produced a manifest with one node, one occurrence and no edges. One unexplored branch says open_binary was not run, and the next probe names open_binary with authority native-analysis-provider. THE RECORD WHAT IT SAW Evidence ev_0e878985 operation inspect_artifact confidence observed · no analysis engine subject ledger-arm64-O1 format mach-o · 33872 bytes sha256 starts 01b5d08b hashes substep inventory_artifact status completed · its own Evidence manifest agm_8e2e5c4c · 1 node · 0 edges runs occurrence occ_35a9bb48 logical_path . · entry_kind file kind executable · hash verified records unexplored_branches[0] reason format-specific-analysis-required open_binary was not run leaves next_probe open_binary authority native-analysis-provider bind one deep provider first next coverage complete-within-substeps · 1 substep · 1 observation · 1 branch · 1 probe · 0 omitted
One cheap read gives a hashed subject, a one-node inventory, and an explicit branch that names open_binary as the next probe. Read from the top. The teal box is the record, the green boxes are what it saw, and the amber box is what it left for a later tool.

What the record is not

The record is not a format parse. It holds no load commands, no sections, no symbols, and no entry point. For those, the next section runs inspect-macho. For a function, Part 4 binds Ghidra with open_binary, the tool the branch names. The whole record is 198 lines, and most of them repeat the subject digest. That repetition is the point: every nested record can stand alone and still name the same bytes.

rea (rea-agents) with the Ghidra provider rea-agents 6.7.0, Ghidra 12.1.4 · 27dc42d · 2026-10-18 · Edition 2026.10