Skip to main content
Glama

analyze_bag

Read-onlyIdempotent

Summarizes a ROS 2 bag at a given path, reporting storage format, duration, message counts, per-topic stats, and detected anomalies for quick inspection.

Instructions

Summarize a ROS 2 bag at path as a BagAnalysis: storage format, duration, message count, per-topic stats and mode_effective. Per topic frequency_hz is (n - 1) / (last - first message time) (frequency_basis topic_span), with first_timestamp_ns, last_timestamp_ns and latched; a latched topic whose messages all fall within 1 s (e.g. /tf_static) has a null frequency_hz. When the bag cannot be read locally or the bounded scan (8 s) is cut, the rate falls back to count / bag duration (bag_duration) and note says why. anomalies lists observed clock steps, silences of steady topics and TF edges, and backward header stamps (topic, time offset, size, no cause); empty means none found by these checks, not clean, and note says if the scan was cut or skipped. Live mode runs ros2 bag info, or rosbags without ros2 or when it fails (reader says which); mock mode returns fixtures for any bag-like path. Raises an MCP error for a missing path, a directory without metadata.yaml or an unreadable bag. Duration: ROS lock, one call at a time, ends within 45 s; busy if held.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "path": "<path>"
    },
    "name": "analyze_bag"
  }
}

Input Schema

NameRequiredDescriptionDefault
pathYesBag path: a `.mcap`, `.db3` or ROS 1 `.bag` file or a `rosbag2_*` directory (with its `metadata.yaml`). Existence and format are checked live; mock accepts any well-formed path.

Output Schema

NameRequiredDescriptionDefault
noteNoWhy the result is less detailed than usual (e.g. rates over the whole bag duration); else `None`.
pathYesBag path as supplied.
readerNoWhat produced this summary: `ros2 bag info`, the `rosbags` library or a mock fixture.
topicsYesPer-topic statistics for every topic present in the bag.
start_nsNoRecord ns of the bag's first message (rosbag2 `starting_time`), the zero of `start_s`/`end_s`; `null` if unreadable.
anomaliesNoObserved clock steps, silences, backward stamps. Empty: none found by these checks, not clean (`note`).
bag_formatNoDetected container: `mcap`, `db3`, `bag` or `unknown`.
duration_sYesBag duration in seconds.
message_countYesTotal number of messages across all recorded topics.
mode_effectiveYes`live` or `mock` (fixtures).
storage_formatNo`mcap`, `sqlite3`, or other storage identifier when known.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changedv0.10.0
    • changedInput schema / properties / path / description
      Previous value: -"Bag path: a `.mcap` or `.db3` file or a `rosbag2_*` directory (`peek_bag_samples` also reads ROS 1 `.bag`; `analyze_bag` does not). Existence and format are checked live; mock accepts any well-formed path."New value: +"Bag path: a `.mcap`, `.db3` or ROS 1 `.bag` file or a `rosbag2_*` directory (with its `metadata.yaml`). Existence and format are checked live; mock accepts any well-formed path."
    • changedOutput schema / description
      Previous value: -"Structured summary of a ROS2 bag."New value: +"Structured summary of a ROS2 bag, from `ros2 bag info`, `rosbags` or a mock fixture."
    • changedOutput schema / properties / anomalies / description
      Previous value: -"Notes on gaps or clock jumps; mock mode only."New value: +"Observed clock steps, silences, backward stamps. Empty: none found by these checks, not clean (`note`)."
    • changedOutput schema / properties / bag_format / description
      Previous value: -"Detected container: `mcap`, `db3`, `bag` or `unknown`; `None` for `ros2 bag info` text."New value: +"Detected container: `mcap`, `db3`, `bag` or `unknown`."
    • addedOutput schema / properties / reader
      Added value: +{
      +  "description": "What produced this summary: `ros2 bag info`, the `rosbags` library or a mock fixture.",
      +  "enum": [
      +    "ros2_cli",
      +    "rosbags",
      +    "fixture",
      +    null
      +  ],
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
  2. Changed2 schema fields changedv0.9.0
    • changedOutput schema / $defs / BagTopicStats / properties / frequency_hz / description
      Previous value: -"Average Hz: (count - 1) over the topic's own time span (see `frequency_basis`); `null` under 2 messages, a zero span, or a latched start-up burst (all within 1 s)."New value: +"(count - 1) / the topic's own span (`frequency_basis`); `null` under 2 messages, zero span or a latched 1 s burst."
    • changedOutput schema / properties / start_ns / description
      Previous value: -"Record time in ns of the bag's first message (rosbag2 `starting_time`): the zero of `peek_bag_samples` `start_s` / `end_s`. `null` when unreadable."New value: +"Record ns of the bag's first message (rosbag2 `starting_time`), the zero of `start_s`/`end_s`; `null` if unreadable."
  3. Changed31 schema fields changedv0.8.0
    • removedOutput schema / $defs / BagTopicStats / properties / first_timestamp_ns / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / BagTopicStats / properties / first_timestamp_ns / default
      Removed value: -null
    • addedOutput schema / $defs / BagTopicStats / properties / first_timestamp_ns / minimum
      Added value: +0
    • addedOutput schema / $defs / BagTopicStats / properties / first_timestamp_ns / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / $defs / BagTopicStats / properties / frequency_basis / anyOf
      Removed value: -[
      -  {
      -    "enum": [
      -      "topic_span",
      -      "bag_duration"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / BagTopicStats / properties / frequency_basis / default
      Removed value: -null
    • addedOutput schema / $defs / BagTopicStats / properties / frequency_basis / enum
      Added value: +[
      +  "topic_span",
      +  "bag_duration",
      +  null
      +]
    • addedOutput schema / $defs / BagTopicStats / properties / frequency_basis / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / $defs / BagTopicStats / properties / frequency_hz / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / BagTopicStats / properties / frequency_hz / default
      Removed value: -null
    • addedOutput schema / $defs / BagTopicStats / properties / frequency_hz / minimum
      Added value: +0
    • addedOutput schema / $defs / BagTopicStats / properties / frequency_hz / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / BagTopicStats / properties / kind / default
      Removed value: -"user"
    • removedOutput schema / $defs / BagTopicStats / properties / last_timestamp_ns / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / BagTopicStats / properties / last_timestamp_ns / default
      Removed value: -null
    • addedOutput schema / $defs / BagTopicStats / properties / last_timestamp_ns / minimum
      Added value: +0
    • addedOutput schema / $defs / BagTopicStats / properties / last_timestamp_ns / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / $defs / BagTopicStats / properties / latched / anyOf
      Removed value: -[
      -  {
      -    "type": "boolean"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / BagTopicStats / properties / latched / default
      Removed value: -null
    • addedOutput schema / $defs / BagTopicStats / properties / latched / type
      Added value: +[
      +  "boolean",
      +  "null"
      +]
    • removedOutput schema / properties / bag_format / anyOf
      Removed value: -[
      -  {
      -    "enum": [
      -      "mcap",
      -      "db3",
      -      "bag",
      -      "unknown"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / bag_format / default
      Removed value: -null
    • addedOutput schema / properties / bag_format / enum
      Added value: +[
      +  "mcap",
      +  "db3",
      +  "bag",
      +  "unknown",
      +  null
      +]
    • addedOutput schema / properties / bag_format / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / note / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / note / default
      Removed value: -null
    • addedOutput schema / properties / note / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • addedOutput schema / properties / start_ns
      Added value: +{
      +  "description": "Record time in ns of the bag's first message (rosbag2 `starting_time`): the zero of `peek_bag_samples` `start_s` / `end_s`. `null` when unreadable.",
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
    • removedOutput schema / properties / storage_format / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / storage_format / default
      Removed value: -null
    • addedOutput schema / properties / storage_format / type
      Added value: +[
      +  "string",
      +  "null"
      +]
  4. Changed42 schema fields changedv0.7.1
    • changedInput schema / properties / path / description
      Previous value: -"Path to a bag: a file ending in `.mcap` or `.db3`, or a `rosbag2_*` directory. `peek_bag_samples` also reads ROS 1 `.bag` files; `analyze_bag` does not (`ros2 bag info` cannot open them). Leading/trailing whitespace is stripped. Null bytes and otherwise malformed filesystem paths are rejected. Existence and bag format are validated by the live adapter (mock mode accepts any well-formed path)."New value: +"Bag path: a `.mcap` or `.db3` file or a `rosbag2_*` directory (`peek_bag_samples` also reads ROS 1 `.bag`; `analyze_bag` does not). Existence and format are checked live; mock accepts any well-formed path."
    • removedInput schema / properties / path / title
      Removed value: -"Path"
    • removedInput schema / title
      Removed value: -"analyze_bagArguments"
    • removedOutput schema / $defs / BagTopicStats / description
      Removed value: -"Per-topic statistics inside a bag analysis result."
    • changedOutput schema / $defs / BagTopicStats / properties / first_timestamp_ns / description
      Previous value: -"Recorded time of the first message on this topic, in nanoseconds (bag receive time, normally epoch). `null` when the bag was summarized from `ros2 bag info` text only, or the topic has no messages."New value: +"Recorded ns of the first message; `null` for text-only summaries or no messages."
    • removedOutput schema / $defs / BagTopicStats / properties / first_timestamp_ns / title
      Removed value: -"First Timestamp Ns"
    • changedOutput schema / $defs / BagTopicStats / properties / frequency_basis / description
      Previous value: -"How `frequency_hz` was computed: `topic_span` (per-topic first and last message times, the accurate one) or `bag_duration` (count divided by whole-bag duration, used when per-topic times could not be read). `null` when there is no rate."New value: +"`topic_span` (accurate) or `bag_duration` (count over the whole bag, understates late topics); `null` without a rate."
    • removedOutput schema / $defs / BagTopicStats / properties / frequency_basis / title
      Removed value: -"Frequency Basis"
    • changedOutput schema / $defs / BagTopicStats / properties / frequency_hz / description
      Previous value: -"Average publish rate in Hz. With `frequency_basis` `topic_span` it is `(message_count - 1) / (last - first message time)` for this topic; with `bag_duration` it is `message_count / bag duration`, which understates the rate of a topic that started late or stopped early. `null` when fewer than 2 messages, a zero time span, or the topic is `latched` and all its messages fall within 1 second (a start-up burst, not a rate). A latched topic published over a longer span keeps its rate. Not a periodic rate for event-driven topics such as `/parameter_events`."New value: +"Average Hz: (count - 1) over the topic's own time span (see `frequency_basis`); `null` under 2 messages, a zero span, or a latched start-up burst (all within 1 s)."
    • removedOutput schema / $defs / BagTopicStats / properties / frequency_hz / title
      Removed value: -"Frequency Hz"
    • addedOutput schema / $defs / BagTopicStats / properties / kind
      Added value: +{
      +  "default": "user",
      +  "description": "`user` (data, incl. `/tf` and `/clock`), `rosbag2_internal` or `ros_builtin` (e.g. `/rosout`).",
      +  "enum": [
      +    "user",
      +    "rosbag2_internal",
      +    "ros_builtin"
      +  ],
      +  "type": "string"
      +}
    • changedOutput schema / $defs / BagTopicStats / properties / last_timestamp_ns / description
      Previous value: -"Recorded time of the last message on this topic; same rules as `first_timestamp_ns`."New value: +"Recorded ns of the last message; same rules."
    • removedOutput schema / $defs / BagTopicStats / properties / last_timestamp_ns / title
      Removed value: -"Last Timestamp Ns"
    • changedOutput schema / $defs / BagTopicStats / properties / latched / description
      Previous value: -"True when a publisher recorded this topic with transient_local durability (late joiners get the last samples, e.g. `/tf_static`, `/rosout`). Such a topic often publishes a start-up burst; when all its messages fall within 1 second `frequency_hz` is `null`. `false` when every recorded publisher was volatile; `null` when the bag carries no QoS information (ROS 1 bags report their latching flag)."New value: +"True if recorded with transient_local durability, false if volatile, `null` without QoS information."
    • removedOutput schema / $defs / BagTopicStats / properties / latched / title
      Removed value: -"Latched"
    • removedOutput schema / $defs / BagTopicStats / properties / message_count / title
      Removed value: -"Message Count"
    • removedOutput schema / $defs / BagTopicStats / properties / message_type / description
      Removed value: -"ROS2 message type recorded for this topic."
    • removedOutput schema / $defs / BagTopicStats / properties / message_type / title
      Removed value: -"Message Type"
    • removedOutput schema / $defs / BagTopicStats / properties / name / description
      Removed value: -"Fully qualified topic name as recorded in the bag."
    • removedOutput schema / $defs / BagTopicStats / properties / name / title
      Removed value: -"Name"
    • removedOutput schema / $defs / BagTopicStats / title
      Removed value: -"BagTopicStats"
    • removedOutput schema / $defs / ParticipantInfo
      Removed value: -{
      -  "additionalProperties": false,
      -  "description": "DDS participant discovered on the configured domain.\n\nCarries identity (`guid`, `name`, `vendor`) plus lifecycle fields\n(`first_seen_ns`, `last_seen_ns`, `status`, `seen_count`).",
      -  "properties": {
      -    "announced_ns": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Nanoseconds since epoch (DDS source timestamp of the participant's most recent announcement, taken from the announcing side's clock; the local clock when the announcer sent none). `None` when the backend does not expose it. Distinct from `first_seen_ns` / `last_seen_ns`, which are TopicForge's own local clock.",
      -      "title": "Announced Ns"
      -    },
      -    "domain_id": {
      -      "description": "DDS domain id the participant is bound to.",
      -      "maximum": 232,
      -      "minimum": 0,
      -      "title": "Domain Id",
      -      "type": "integer"
      -    },
      -    "first_seen_ns": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Wall-clock timestamp (nanoseconds since epoch) of the **first** discovery sample TopicForge observed for this participant. `None` when the adapter does not track lifecycle.",
      -      "title": "First Seen Ns"
      -    },
      -    "guid": {
      -      "description": "DDS Global Unique Identifier of the participant: hex string, stable across discovery events within a single deployment.",
      -      "title": "Guid",
      -      "type": "string"
      -    },
      -    "hostname": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Hostname announced in discovery (Cyclone `__Hostname` property). `None` when the vendor does not announce it.",
      -      "title": "Hostname"
      -    },
      -    "is_observer": {
      -      "default": false,
      -      "description": "True for TopicForge's own read-only observer participant, which joins the domain to watch it and appears in this list; false for every other participant.",
      -      "title": "Is Observer",
      -      "type": "boolean"
      -    },
      -    "last_seen_ns": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Wall-clock timestamp (nanoseconds since epoch) of the **most recent** discovery sample observed. Used by `participant_events` to distinguish currently-active participants from those that left the bus. `None` when the adapter does not track lifecycle.",
      -      "title": "Last Seen Ns"
      -    },
      -    "lost_ns": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Nanoseconds since epoch of the moment the participant left, once `status` is `left`; `None` while it is active. How precise it is depends on `lost_time_source`. It is an upper bound of when the participant died: after a clean shutdown it is the exact leave time, after a crash it is when the lease expired, and the two cannot be told apart. The process died at or before `lost_ns`, and at most one lease earlier (10 s Cyclone default, 20 s Fast, 100 s RTI).",
      -      "title": "Lost Ns"
      -    },
      -    "lost_time_source": {
      -      "anyOf": [
      -        {
      -          "enum": [
      -            "dds_source_timestamp",
      -            "observed_local"
      -          ],
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Where `lost_ns` comes from: `dds_source_timestamp` (timestamp carried by the discovery dispose) or `observed_local` (the moment TopicForge noticed, the weakest). `None` while active.",
      -      "title": "Lost Time Source"
      -    },
      -    "mode_effective": {
      -      "description": "Runtime mode the adapter served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Lets a caller tell a real graph from a demo one without calling `health_check`.",
      -      "enum": [
      -        "mock",
      -        "live"
      -      ],
      -      "title": "Mode Effective",
      -      "type": "string"
      -    },
      -    "name": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Participant name the application announced through the standard DDS EntityName QoS (PID_ENTITY_NAME in RTPS discovery), for example `lidar_driver`. `None` when the application did not set one (Dust DDS cannot) or the backend does not expose it.",
      -      "title": "Name"
      -    },
      -    "seen_count": {
      -      "default": 1,
      -      "description": "Number of distinct discovery samples observed for this participant across all calls to `list_participants` during this server's lifetime. Starts at 1 and increments on each observation.",
      -      "minimum": 1,
      -      "title": "Seen Count",
      -      "type": "integer"
      -    },
      -    "status": {
      -      "default": "unknown",
      -      "description": "Lifecycle status. `active` means TopicForge has a recent discovery sample for this GUID and the bus has not signalled removal. `left` means the participant was observed earlier but has since disappeared (a Fast DDS `REMOVED` callback or a Cyclone polling delta). `unknown` when the adapter does not track lifecycle.",
      -      "enum": [
      -        "active",
      -        "left",
      -        "unknown"
      -      ],
      -      "title": "Status",
      -      "type": "string"
      -    },
      -    "vendor": {
      -      "description": "DDS implementation that announced this participant, decoded from the OMG-RTPS `vendor_id` field on the discovery sample. `cyclone` (Eclipse Cyclone DDS), `fast` (eProsima Fast DDS), `rti` (RTI Connext), `rti_micro` (RTI Connext Micro), `opensplice` (ADLink OpenSplice), `opendds` (OCI OpenDDS), `coredx` (Twin Oaks CoreDX), `intercom` (Kongsberg InterCOM), `dust` (S2E Dust DDS). `mock` is reserved for synthetic fixtures. `unknown` means the vendor could not be determined: TopicForge reads it from the vendor prefix of the participant GUID, and some vendors (for example Dust DDS and RTI Connext) do not put their vendor id there, while the Cyclone Python binding does not expose the RTPS header vendor id. The participant is still reported; see `vendor_source`. Any conformant DDS-RTPS participant should appear through standard discovery; Cyclone DDS and Dust DDS have been observed on a live bus. See `docs/dds-interop-matrix.md`.",
      -      "enum": [
      -        "cyclone",
      -        "fast",
      -        "rti",
      -        "rti_micro",
      -        "opensplice",
      -        "opendds",
      -        "coredx",
      -        "intercom",
      -        "dust",
      -        "mock",
      -        "unknown"
      -      ],
      -      "title": "Vendor",
      -      "type": "string"
      -    },
      -    "vendor_source": {
      -      "default": "none",
      -      "description": "Where `vendor` came from: `guid_prefix` when it was read from the vendor prefix of the participant GUID, `none` when the vendor is unknown (or synthetic in mock mode).",
      -      "enum": [
      -        "guid_prefix",
      -        "none"
      -      ],
      -      "title": "Vendor Source",
      -      "type": "string"
      -    }
      -  },
      -  "required": [
      -    "guid",
      -    "vendor",
      -    "domain_id",
      -    "mode_effective"
      -  ],
      -  "title": "ParticipantInfo",
      -  "type": "object"
      -}
    • changedOutput schema / description
      Previous value: -"Structured summary of a ROS2 bag.\n\nThe fields `bag_format`, `samples_decoded_count`,\n`recording_duration_ns` and `participants_recorded` are populated only\nwhen the `rosbags`-backed reader runs; the `ros2 bag info` path leaves\nthem at their defaults."New value: +"Structured summary of a ROS2 bag."
    • changedOutput schema / properties / anomalies / description
      Previous value: -"Human-readable notes about gaps, clock jumps, or other oddities. Populated in mock mode only; live mode does not detect anomalies."New value: +"Notes on gaps or clock jumps; mock mode only."
    • removedOutput schema / properties / anomalies / title
      Removed value: -"Anomalies"
    • changedOutput schema / properties / bag_format / description
      Previous value: -"Concrete bag container format detected by the reader: `mcap` (Foxglove MCAP), `db3` (ROS2 rosbag2 SQLite), `bag` (ROS1 legacy chunked), or `unknown` when the reader could not classify. `None` when the bag was summarized from `ros2 bag info` text, which carries no format information."New value: +"Detected container: `mcap`, `db3`, `bag` or `unknown`; `None` for `ros2 bag info` text."
    • removedOutput schema / properties / bag_format / title
      Removed value: -"Bag Format"
    • addedOutput schema / properties / duration_s
      Added value: +{
      +  "description": "Bag duration in seconds.",
      +  "minimum": 0,
      +  "type": "number"
      +}
    • removedOutput schema / properties / duration_seconds
      Removed value: -{
      -  "description": "Total bag duration, in seconds (wall clock between first and last message).",
      -  "minimum": 0,
      -  "title": "Duration Seconds",
      -  "type": "number"
      -}
    • removedOutput schema / properties / message_count / title
      Removed value: -"Message Count"
    • changedOutput schema / properties / mode_effective / description
      Previous value: -"Runtime mode the adapter served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Lets a caller tell a real graph from a demo one without calling `health_check`."New value: +"`live` or `mock` (fixtures)."
    • removedOutput schema / properties / mode_effective / title
      Removed value: -"Mode Effective"
    • changedOutput schema / properties / note / description
      Previous value: -"Why the result is less detailed than usual, for example per-topic rates computed over the whole bag duration because the bag was too large to read per-topic message times. `None` when there is nothing to add."New value: +"Why the result is less detailed than usual (e.g. rates over the whole bag duration); else `None`."
    • removedOutput schema / properties / note / title
      Removed value: -"Note"
    • removedOutput schema / properties / participants_recorded
      Removed value: -{
      -  "description": "DDS participants recorded in the bag when the container format embeds participant metadata. MCAP can carry it via channel metadata records; ROS2 `.db3` and ROS1 `.bag` generally do not. Empty list when not available, which is the common case.",
      -  "items": {
      -    "$ref": "#/$defs/ParticipantInfo"
      -  },
      -  "title": "Participants Recorded",
      -  "type": "array"
      -}
    • changedOutput schema / properties / path / description
      Previous value: -"Path to the analyzed bag, as supplied by the caller. May point to a file (`.mcap`, `.db3`, or ROS 1 `.bag` for `peek_bag_samples`) or to a `rosbag2_*` directory."New value: +"Bag path as supplied."
    • removedOutput schema / properties / path / title
      Removed value: -"Path"
    • removedOutput schema / properties / recording_duration_ns
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Recording duration in nanoseconds when readable from the bag's index. `None` when only `ros2 bag info` text was parsed; `duration_seconds` (float) is the always-populated fallback that downstream LLM consumers should prefer when this is `None`.",
      -  "title": "Recording Duration Ns"
      -}
    • removedOutput schema / properties / samples_decoded_count
      Removed value: -{
      -  "default": 0,
      -  "description": "Total decoded sample count across all topics produced by the bag reader. `0` when the reader only parsed metadata or when `rosbags` is not installed on the host. Use `peek_bag_samples` to pull the actual sample payloads for a specific topic.",
      -  "minimum": 0,
      -  "title": "Samples Decoded Count",
      -  "type": "integer"
      -}
    • removedOutput schema / properties / storage_format / title
      Removed value: -"Storage Format"
    • removedOutput schema / properties / topics / title
      Removed value: -"Topics"
    • changedOutput schema / required
      Previous value: -[
      -  "path",
      -  "duration_seconds",
      -  "message_count",
      -  "topics",
      -  "mode_effective"
      -]New value: +[
      +  "path",
      +  "duration_s",
      +  "message_count",
      +  "topics",
      +  "mode_effective"
      +]
  5. First observedv0.5.6

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Far beyond the annotations (readOnly, idempotent, non-destructive), it discloses the frequency formula and basis, the latched-topic exception with a concrete example (`/tf_static`), the count/duration fallback with a reason in `note`, and the 8 s bounded scan. It also warns that an empty `anomalies` list is not proof of a clean bag and documents the single-call 45 s lock with a `busy` outcome.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the purpose and then dense but ordered, moving from output shape to fallbacks to errors to timing. Some of the per-field elaboration overlaps with the existing output schema, which slightly exceeds what the description needs to carry.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read tool with an output schema, this covers everything an agent needs: what is returned, how rates are computed, what the fallback means, what triggers an error, and the concurrency/duration constraint. Nothing material is left to inference.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the `path` description already lists accepted file types, so the baseline is 3. The description adds meaning the schema lacks: existence and format are validated live, while mock mode accepts any well-formed bag-like path.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause gives a specific verb ('Summarize'), a specific resource ('a ROS 2 bag at `path`'), and the return type (`BagAnalysis`). That framing implicitly separates it from message-sampling siblings like peek_bag_samples, and an agent can select it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives conditional context (live mode uses `ros2 bag info` or `rosbags`; mock mode returns fixtures for any bag-like path) and enumerates when it raises an error. It never states when to prefer this over siblings such as peek_bag_samples or topic_metrics, so the when-to-use routing is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.