topicforge 0.7.0__tar.gz → 0.7.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. {topicforge-0.7.0 → topicforge-0.7.2}/CHANGELOG.md +101 -1
  2. {topicforge-0.7.0 → topicforge-0.7.2}/PKG-INFO +10 -9
  3. {topicforge-0.7.0 → topicforge-0.7.2}/README.md +9 -8
  4. {topicforge-0.7.0 → topicforge-0.7.2}/docs/CLIENTS.md +17 -17
  5. {topicforge-0.7.0 → topicforge-0.7.2}/docs/CONTRACT.md +213 -14
  6. {topicforge-0.7.0 → topicforge-0.7.2}/docs/DDS_QUICKSTART.md +2 -2
  7. {topicforge-0.7.0 → topicforge-0.7.2}/docs/EVAL.md +14 -0
  8. {topicforge-0.7.0 → topicforge-0.7.2}/docs/TESTING.md +5 -5
  9. topicforge-0.7.2/docs/TOOLS.md +503 -0
  10. {topicforge-0.7.0 → topicforge-0.7.2}/docs/TROUBLESHOOTING.md +1 -1
  11. {topicforge-0.7.0 → topicforge-0.7.2}/docs/TUTORIEL.md +1 -1
  12. topicforge-0.7.2/docs/VALIDATION.md +44 -0
  13. {topicforge-0.7.0 → topicforge-0.7.2}/docs/dds-interop-matrix.md +2 -2
  14. {topicforge-0.7.0 → topicforge-0.7.2}/examples/README.md +1 -1
  15. {topicforge-0.7.0 → topicforge-0.7.2}/plugin/README.md +1 -1
  16. {topicforge-0.7.0 → topicforge-0.7.2}/plugin/pyproject.toml +2 -2
  17. {topicforge-0.7.0 → topicforge-0.7.2}/pyproject.toml +1 -1
  18. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/ground_truth/README.md +25 -3
  19. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/__init__.py +1 -1
  20. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/base.py +3 -0
  21. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/dds_helpers.py +1 -1
  22. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/dds_introspection.py +12 -0
  23. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/discovery_tracker.py +39 -9
  24. topicforge-0.7.2/src/topicforge/adapters/common/qos_fixes.py +518 -0
  25. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/qos_scan.py +50 -6
  26. topicforge-0.7.2/src/topicforge/adapters/common/ros_discovery.py +433 -0
  27. topicforge-0.7.2/src/topicforge/adapters/common/spawned_pids.py +35 -0
  28. topicforge-0.7.2/src/topicforge/adapters/common/tf_tree.py +403 -0
  29. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/composite.py +19 -1
  30. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/dds_cyclone/adapter.py +44 -3
  31. topicforge-0.7.2/src/topicforge/adapters/dds_cyclone/ros_info.py +69 -0
  32. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/dds_fast/adapter.py +4 -0
  33. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/adapter.py +19 -0
  34. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/echo_stream.py +2 -0
  35. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/process_runner.py +2 -0
  36. topicforge-0.7.2/src/topicforge/adapters/ros2_live/tf_capture.py +272 -0
  37. topicforge-0.7.2/src/topicforge/adapters/ros2_live/tf_parsers.py +45 -0
  38. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_mock/adapter.py +17 -2
  39. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_mock/fixtures.py +40 -4
  40. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_mock/node_fixtures.py +6 -0
  41. topicforge-0.7.2/src/topicforge/adapters/ros2_mock/tf_fixtures.py +58 -0
  42. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/constants.py +10 -0
  43. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/models/__init__.py +8 -0
  44. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/models/nodes.py +11 -21
  45. topicforge-0.7.2/src/topicforge/models/schemas.py +1276 -0
  46. topicforge-0.7.2/src/topicforge/models/summaries.py +242 -0
  47. topicforge-0.7.2/src/topicforge/models/tf.py +107 -0
  48. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/server/prompts.py +3 -2
  49. topicforge-0.7.2/src/topicforge/services/dds_views.py +165 -0
  50. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/inspector.py +114 -9
  51. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/tools/guard.py +2 -2
  52. topicforge-0.7.2/src/topicforge/tools/handlers.py +753 -0
  53. topicforge-0.7.2/src/topicforge/tools/schema_compact.py +60 -0
  54. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/_prompts.json +2 -2
  55. topicforge-0.7.2/tests/contract/analyze_bag.json +219 -0
  56. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/detect_qos_mismatches.json +54 -129
  57. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/get_node_info.json +13 -40
  58. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/get_topic_info.json +9 -30
  59. topicforge-0.7.2/tests/contract/health_check.json +303 -0
  60. topicforge-0.7.2/tests/contract/inspect_tf.json +344 -0
  61. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/list_endpoints.json +73 -128
  62. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/list_nodes.json +4 -18
  63. topicforge-0.7.2/tests/contract/list_participants.json +310 -0
  64. topicforge-0.7.2/tests/contract/list_topics.json +96 -0
  65. topicforge-0.7.2/tests/contract/participant_events.json +239 -0
  66. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/peek_bag_samples.json +92 -209
  67. {topicforge-0.7.0 → topicforge-0.7.2}/tests/contract/peek_dds_samples.json +91 -207
  68. topicforge-0.7.2/tests/contract/sample_messages.json +1104 -0
  69. topicforge-0.7.2/tests/contract/topic_metrics.json +181 -0
  70. topicforge-0.7.2/tests/fixtures/ground_truth/omnisim_071_morning_results.json +1 -0
  71. topicforge-0.7.2/tests/fixtures/ground_truth/omnisim_071_morning_truth.json +1 -0
  72. topicforge-0.7.2/tests/fixtures/ground_truth/omnisim_071_rerun_results.json +1 -0
  73. topicforge-0.7.2/tests/fixtures/ground_truth/omnisim_071_rerun_truth.json +1 -0
  74. topicforge-0.7.2/tests/fixtures/ros_discovery/humble_two_nodes.hex +1 -0
  75. topicforge-0.7.2/tests/fixtures/ros_discovery/jazzy_two_nodes.hex +1 -0
  76. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/ground_truth.py +50 -1
  77. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/publisher.py +34 -1
  78. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/test_live_adapter.py +29 -0
  79. topicforge-0.7.2/tests/test_composite_ghosts.py +105 -0
  80. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_contract_shape.py +2 -1
  81. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_contract_v2.py +6 -1
  82. topicforge-0.7.2/tests/test_cyclone_ros_info.py +111 -0
  83. topicforge-0.7.2/tests/test_friction_fixes.py +315 -0
  84. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_ground_truth_compare.py +266 -3
  85. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_honest_outputs.py +1 -1
  86. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_http_transport.py +1 -1
  87. topicforge-0.7.2/tests/test_qos_fixes.py +362 -0
  88. topicforge-0.7.2/tests/test_restarts_by_node.py +65 -0
  89. topicforge-0.7.2/tests/test_ros_discovery.py +394 -0
  90. topicforge-0.7.2/tests/test_tf_tools.py +514 -0
  91. topicforge-0.7.2/tests/test_tf_tree.py +197 -0
  92. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_tool_annotations.py +2 -2
  93. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_tool_descriptions.py +2 -0
  94. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_tools_integration.py +5 -2
  95. topicforge-0.7.0/docs/TOOLS.md +0 -452
  96. topicforge-0.7.0/docs/VALIDATION.md +0 -19
  97. topicforge-0.7.0/src/topicforge/models/schemas.py +0 -1555
  98. topicforge-0.7.0/src/topicforge/models/summaries.py +0 -328
  99. topicforge-0.7.0/src/topicforge/tools/handlers.py +0 -870
  100. topicforge-0.7.0/tests/contract/analyze_bag.json +0 -243
  101. topicforge-0.7.0/tests/contract/health_check.json +0 -332
  102. topicforge-0.7.0/tests/contract/list_participants.json +0 -293
  103. topicforge-0.7.0/tests/contract/list_topics.json +0 -117
  104. topicforge-0.7.0/tests/contract/participant_events.json +0 -216
  105. topicforge-0.7.0/tests/contract/sample_messages.json +0 -1223
  106. topicforge-0.7.0/tests/contract/topic_metrics.json +0 -201
  107. {topicforge-0.7.0 → topicforge-0.7.2}/.gitignore +0 -0
  108. {topicforge-0.7.0 → topicforge-0.7.2}/LICENSE +0 -0
  109. {topicforge-0.7.0 → topicforge-0.7.2}/docs/MIGRATION-0.7.md +0 -0
  110. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/00_hello_pub_sub/README.md +0 -0
  111. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/01_who_is_on_the_bus/README.md +0 -0
  112. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/02_why_cant_they_talk/README.md +0 -0
  113. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/03_a_node_crashed/README.md +0 -0
  114. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/04_late_joiner_misses_data/README.md +0 -0
  115. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/05_reliability_in_code/README.md +0 -0
  116. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/06_durability_late_joiner_in_code/README.md +0 -0
  117. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/07_deadline_in_code/README.md +0 -0
  118. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/08_crash_seen_from_inside/README.md +0 -0
  119. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/10_lidar_silent_after_driver_swap/README.md +0 -0
  120. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/11_who_talks_to_whom/README.md +0 -0
  121. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/12_safety_monitor_dropout/README.md +0 -0
  122. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/13_deadline_not_offered/README.md +0 -0
  123. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/14_restart_loop/README.md +0 -0
  124. {topicforge-0.7.0 → topicforge-0.7.2}/examples/dds/README.md +0 -0
  125. {topicforge-0.7.0 → topicforge-0.7.2}/plugin/LICENSE +0 -0
  126. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/agent_eval/README.md +0 -0
  127. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/README.md +0 -0
  128. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/cyclone_c/README.md +0 -0
  129. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/cyclone_cpp/README.md +0 -0
  130. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/cyclone_rust/README.md +0 -0
  131. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/dust_py/README.md +0 -0
  132. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/fast_publisher_cpp/README.md +0 -0
  133. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/fast_py/README.md +0 -0
  134. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/opensplice_publisher/README.md +0 -0
  135. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/rti_c/README.md +0 -0
  136. {topicforge-0.7.0 → topicforge-0.7.2}/scripts/integration/publishers/rti_cpp/README.md +0 -0
  137. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/__main__.py +0 -0
  138. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/__init__.py +0 -0
  139. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/__init__.py +0 -0
  140. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/bag_kind.py +0 -0
  141. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/cdr_decoder.py +0 -0
  142. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/endpoints.py +0 -0
  143. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/lifecycle.py +0 -0
  144. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/metrics_buffer.py +0 -0
  145. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/nodes.py +0 -0
  146. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/qos_analyzer.py +0 -0
  147. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/qos_endpoints.py +0 -0
  148. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/qos_normalize.py +0 -0
  149. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/ros_names.py +0 -0
  150. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/stamps.py +0 -0
  151. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/topic_filter.py +0 -0
  152. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/common/xtypes.py +0 -0
  153. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/dds_cyclone/__init__.py +0 -0
  154. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/dds_fast/__init__.py +0 -0
  155. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/__init__.py +0 -0
  156. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/echo_parser.py +0 -0
  157. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/node_parsers.py +0 -0
  158. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/parsers.py +0 -0
  159. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/process_tree.py +0 -0
  160. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_live/sample_extras.py +0 -0
  161. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/adapters/ros2_mock/__init__.py +0 -0
  162. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/budget.py +0 -0
  163. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/config/__init__.py +0 -0
  164. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/config/settings.py +0 -0
  165. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/server/__init__.py +0 -0
  166. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/server/app.py +0 -0
  167. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/server/http.py +0 -0
  168. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/__init__.py +0 -0
  169. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/bag_service.py +0 -0
  170. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/bag_stats.py +0 -0
  171. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/factory.py +0 -0
  172. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/health.py +0 -0
  173. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/sample_budget.py +0 -0
  174. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/summaries/__init__.py +0 -0
  175. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/summaries/_common.py +0 -0
  176. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/summaries/laser_scan.py +0 -0
  177. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/summaries/motion.py +0 -0
  178. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/summaries/rate.py +0 -0
  179. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/services/summaries/sensor_data.py +0 -0
  180. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/telemetry/__init__.py +0 -0
  181. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/telemetry/client.py +0 -0
  182. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/tools/__init__.py +0 -0
  183. {topicforge-0.7.0 → topicforge-0.7.2}/src/topicforge/tools/annotations.py +0 -0
  184. {topicforge-0.7.0 → topicforge-0.7.2}/tests/__init__.py +0 -0
  185. {topicforge-0.7.0 → topicforge-0.7.2}/tests/conftest.py +0 -0
  186. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ground_truth/omnisim_064_results.json +0 -0
  187. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ground_truth/omnisim_064_truth.json +0 -0
  188. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/image_noarr.yaml +0 -0
  189. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/image_trunc4.yaml +0 -0
  190. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/scan_edge.yaml +0 -0
  191. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/scan_noarr.yaml +0 -0
  192. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/scan_trunc128.yaml +0 -0
  193. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/scan_trunc3.yaml +0 -0
  194. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/string_latched.yaml +0 -0
  195. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_echo/twist.yaml +0 -0
  196. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/node_info_humble.txt +0 -0
  197. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/node_info_no_param_services.txt +0 -0
  198. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/node_info_not_found.txt +0 -0
  199. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/node_list_duplicates.txt +0 -0
  200. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/node_list_empty.txt +0 -0
  201. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/node_list_plain.txt +0 -0
  202. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/node_list_warning_stdout.txt +0 -0
  203. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/param_dump_humble.yaml +0 -0
  204. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_node/param_dump_secrets.yaml +0 -0
  205. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_topic_info_verbose_clock.txt +0 -0
  206. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_topic_info_verbose_cmd_vel.txt +0 -0
  207. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_topic_info_verbose_parameter_events.txt +0 -0
  208. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_topic_info_verbose_scan.txt +0 -0
  209. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_topic_info_verbose_tf.txt +0 -0
  210. {topicforge-0.7.0 → topicforge-0.7.2}/tests/fixtures/ros2_topic_info_verbose_tf_static.txt +0 -0
  211. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/__init__.py +0 -0
  212. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/Dockerfile +0 -0
  213. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/__init__.py +0 -0
  214. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/blocked_node.py +0 -0
  215. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/entrypoint.sh +0 -0
  216. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/ros2/run_bench.py +0 -0
  217. {topicforge-0.7.0 → topicforge-0.7.2}/tests/integration/test_real_bus.py +0 -0
  218. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_analyze_bag_multi_format.py +0 -0
  219. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_bag_omnisim_humble.py +0 -0
  220. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_bag_service.py +0 -0
  221. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_bag_stats.py +0 -0
  222. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_bag_summaries.py +0 -0
  223. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_cdr_decoder.py +0 -0
  224. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_composite_adapter.py +0 -0
  225. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_config.py +0 -0
  226. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_contract_snapshots.py +0 -0
  227. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_cyclone_adapter.py +0 -0
  228. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_dds_cross_vendor.py +0 -0
  229. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_dds_helpers.py +0 -0
  230. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_dds_inactive_reason.py +0 -0
  231. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_dds_introspection.py +0 -0
  232. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_dds_qos_normalization.py +0 -0
  233. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_dds_schemas.py +0 -0
  234. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_discovery_tracker.py +0 -0
  235. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_echo_parser.py +0 -0
  236. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_echo_stream.py +0 -0
  237. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_endpoints.py +0 -0
  238. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_example_node_spec.py +0 -0
  239. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_factory.py +0 -0
  240. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_fast_adapter.py +0 -0
  241. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_field_names.py +0 -0
  242. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_health.py +0 -0
  243. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_history_and_hints.py +0 -0
  244. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_inspector.py +0 -0
  245. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_lifecycle_buffer.py +0 -0
  246. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_live_adapter_graph.py +0 -0
  247. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_live_adapter_parse.py +0 -0
  248. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_live_adapter_subprocess.py +0 -0
  249. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_live_sample_notes.py +0 -0
  250. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_metrics_buffer.py +0 -0
  251. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_mock_adapter.py +0 -0
  252. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_node_logic.py +0 -0
  253. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_node_parsers.py +0 -0
  254. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_node_tools.py +0 -0
  255. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_peek_bag_samples.py +0 -0
  256. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_process_runner.py +0 -0
  257. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_process_tree.py +0 -0
  258. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_prompts.py +0 -0
  259. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_qos_analyzer.py +0 -0
  260. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_qos_endpoints.py +0 -0
  261. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_qos_scan.py +0 -0
  262. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_rate_verdicts.py +0 -0
  263. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_sample_options.py +0 -0
  264. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_sample_summary_flow.py +0 -0
  265. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_server_guard.py +0 -0
  266. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_server_info_version.py +0 -0
  267. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_server_lanes.py +0 -0
  268. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_stamps.py +0 -0
  269. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_summaries.py +0 -0
  270. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_telemetry.py +0 -0
  271. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_topic_metrics.py +0 -0
  272. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_version_consistency.py +0 -0
  273. {topicforge-0.7.0 → topicforge-0.7.2}/tests/test_xtypes.py +0 -0
@@ -7,6 +7,104 @@ and this project adheres to [Semantic Versioning 2.0.0](https://semver.org/spec/
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.2] - 2026-10-18
11
+
12
+ TF tree inspection, ROS 2 node names on DDS participants, and a flag for the `ros2` CLI
13
+ processes TopicForge itself spawns. Additive only: no field or input was renamed, removed or
14
+ retyped (`docs/CONTRACT.md` section 9). Validated on the Docker ROS 2 bench (Humble and Jazzy,
15
+ rmw_fastrtps and rmw_cyclonedds).
16
+
17
+ ### Added
18
+
19
+ - `inspect_tf`, the 15th tool (additive, `docs/CONTRACT.md` section 9.8): rebuilds the TF tree
20
+ from `/tf_static` (latched, read once) and `/tf` (listened to for `window_s`, 1 to 20 s) and
21
+ returns `TfReport`: every frame with its parent, `kind` (static, dynamic, both), `age_s`,
22
+ `stale`, and two rates (`observed_frequency_hz` on wall time, `sim_frequency_hz` on header
23
+ stamps), the `roots`, and `findings` (`stale`, `two_parents`, `disconnected`,
24
+ `static_and_dynamic`, `cycle`, `no_path`). Ages are measured on the stamps against the newest
25
+ `/tf` stamp, so they hold on sim time; `real_time_factor` says when the robot runs on
26
+ `/clock`. `source_frame` and `target_frame` give the chain between two frames in `path`.
27
+ ROS lane, `ros2` CLI only (a DDS-only setup raises the usual error); the mock serves a fixed
28
+ tree with one stale frame. The mock `/tf` sample no longer carries `base_link -> laser`,
29
+ which moved to the new mock topic `/tf_static`.
30
+ - `list_participants` fills `node_names` (and `node_names_source` `ros_discovery_info`) on
31
+ the Cyclone backend: a fourth reader on `ros_discovery_info` plus a hand-written XCDR1
32
+ decoder (`adapters/common/ros_discovery.py`) that accepts the 24-byte (Humble) and
33
+ 16-byte (Jazzy and later) gid. Checked on the Docker ROS 2 bench (Humble and Jazzy, rmw_fastrtps
34
+ and rmw_cyclonedds). Mock participants get names from the mock node fixtures.
35
+ - `ParticipantInfo.is_topicforge_cli`: the `ros2` CLI processes TopicForge itself spawns
36
+ (right after `get_node_info` they stay on the bus 0.3-2 s, so a 7-participant bus
37
+ listed 8) are flagged, never hidden, and the listing `note` explains them. Matched by
38
+ `_ros2cli_<pid>` node name, or (only when the participant's hostname is known and is this
39
+ machine's) Fast DDS GUID pid bits or Cyclone `__Pid`, against a 30 s ring of pids recorded
40
+ by the process runner; a participant announcing another host is never flagged. Limit: on
41
+ Windows `ros2.exe` spawns a child process, so the recorded pid rarely matches and the flag
42
+ mostly falls back to the time-correlation note (`may be its ghosts`).
43
+ - `ParticipantListing.restarts_by_node`: `restarts_by_name` keyed by ROS 2 node name.
44
+
45
+ ### Changed
46
+
47
+ - `MiddlewareAdapter` gains `capture_tf(window_s)` (needed by `inspect_tf`). Third-party
48
+ adapters implementing the protocol must add it; DDS-only ones can raise the DDS-only error
49
+ (`DDS_ONLY_ERROR_MSG`).
50
+
51
+ ### Fixed
52
+
53
+ - Ground-truth comparator (`scripts/ground_truth`, tooling only: no change to the MCP tools or
54
+ the output contract). Two real OmniSim runs on 0.7.1 showed false FAILs that were the host's
55
+ or the harness's doing, not TopicForge's: wall-clock frequency rows are now WARN at most when
56
+ the kit's real-time factor is under 0.5 or the wall/sim ratios of the kit and TopicForge
57
+ differ by more than 25 percent (simulated-time rows still gate); `/parameter_events` and
58
+ `/rosout` writer/reader counts are no longer compared; `ros2` CLI participants started by
59
+ TopicForge itself (`is_topicforge_cli` or a `_ros2cli_` node name) are ignored and reported.
60
+ `drive.py` now runs the DDS calls before `get_node_info` and settles 3 s before them and at the end.
61
+
62
+ ## [0.7.1] - 2026-10-14
63
+
64
+ QoS fix suggestions and agent-friction fixes from the blind evaluation (`docs/EVAL.md`). Additive only: no field or
65
+ input was renamed, removed or retyped (`docs/CONTRACT.md` section 9).
66
+
67
+ ### Added
68
+
69
+ - `detect_qos_mismatches` fills `suggested_fixes` (output contract 2, additive; see
70
+ `docs/CONTRACT.md` section 3.1): "diagnose, propose the exact fix, verify". Each QoS
71
+ mismatch report and each `partition` split gets up to one fix per side that can change
72
+ (`MismatchReport.suggested_fixes`, and the new `NotMatchedPair.suggested_fixes`), with its
73
+ tradeoff and a `verify_with` call. A ROS 2 topic with a Reliability or Durability finding
74
+ gets a `qos_override` parameter-file entry; every other case gets a `dds_profile` (Fast DDS
75
+ XML plus the cyclonedds-python equivalent, since Cyclone DDS has no XML QoS profile).
76
+ Covered: Reliability, Durability, Deadline, Liveliness, Ownership, LatencyBudget and
77
+ Partition; other findings get a hint instead. Identical findings on a topic share the
78
+ first report's fixes. Text only: TopicForge never applies a fix, and a test fails any
79
+ suggestion containing a stop, remove or write verb.
80
+ - `list_participants` and `participant_events`: `restarts_by_name` (`{name: {lives,
81
+ departures}}` for names seen with several GUIDs or lost) and `restarts_note`, so an agent
82
+ no longer counts GUIDs to find a restart loop.
83
+ - `participant_events`: `age_s` on each event, seconds between the event and the response
84
+ (`null` in mock mode).
85
+ - `detect_qos_mismatches`: `summary`, a one-line reading of the scan that says when pairs are
86
+ not matched and no data flows, even with an empty `reports`.
87
+ - `list_endpoints`: optional input `fields` (`full` default, or `compact`) with the output
88
+ fields `fields` and `qos_summary`; compact replaces each `qos` by a one-line summary and
89
+ drops `type_id`, `announced_ns` and `ros_topic_note`.
90
+
91
+ ### Changed
92
+
93
+ - `tools/list` is about 37 percent smaller (about 178 KB to 113 KB compact), because some
94
+ clients truncated it: tool and field descriptions are shorter, and the generated schema
95
+ titles and nested-model docstrings are no longer served. Names, types, defaults and
96
+ constraints are unchanged. The long explanations moved to `docs/CONTRACT.md` section 9.
97
+ - `domain_id` on `list_participants`, `participant_events`, `topic_metrics` and
98
+ `list_endpoints`: the description now opens with "Ignored", and a non-zero value that
99
+ differs from the domain joined at startup adds an explicit sentence to the response `note`
100
+ (the response `domain_id` already named the observed domain).
101
+
102
+ ### Fixed
103
+
104
+ - `scripts/ground_truth/compare.py` counts only active DDS participants: the `ros2` CLI
105
+ processes that `get_node_info` starts stay listed with status `left` and inflated the count
106
+ (found on the OmniSim kit run of 2026-10-14 on 0.7.0: 76 checks passed, 0 failed).
107
+
10
108
  ## [0.7.0] - 2026-10-12
11
109
 
12
110
  Breaking release: output contract 2 (see `docs/MIGRATION-0.7.md`), the move to the MCP SDK
@@ -1615,7 +1713,9 @@ Initial MVP release of TopicForge: ROS Topic Inspector & Bag Analyzer MCP server
1615
1713
  - The write path (publishing, commanding robots) is intentionally out of scope for the MVP.
1616
1714
  - `analyze_bag` in live mode parses `ros2 bag info` text output; deeper anomaly detection remains mock-only for now.
1617
1715
 
1618
- [Unreleased]: https://github.com/yaniswav/TopicForge/compare/v0.7.0...HEAD
1716
+ [Unreleased]: https://github.com/yaniswav/TopicForge/compare/v0.7.2...HEAD
1717
+ [0.7.2]: https://github.com/yaniswav/TopicForge/compare/v0.7.1...v0.7.2
1718
+ [0.7.1]: https://github.com/yaniswav/TopicForge/compare/v0.7.0...v0.7.1
1619
1719
  [0.7.0]: https://github.com/yaniswav/TopicForge/compare/v0.6.4...v0.7.0
1620
1720
  [0.6.4]: https://github.com/yaniswav/TopicForge/compare/v0.6.3...v0.6.4
1621
1721
  [0.6.3]: https://github.com/yaniswav/TopicForge/compare/v0.6.2...v0.6.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: topicforge
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: ROS Topic Inspector & Bag Analyzer MCP server for AI agents
5
5
  Project-URL: Homepage, https://github.com/yaniswav/TopicForge
6
6
  Project-URL: Repository, https://github.com/yaniswav/TopicForge
@@ -73,9 +73,9 @@ A read-only MCP (Model Context Protocol) server that lets an AI agent inspect a
73
73
 
74
74
  Every tool also declares itself read-only in the MCP protocol (`readOnlyHint`, `destructiveHint=false`, `idempotentHint`, with an honest `openWorldHint`), and a test fails if any tool lacks it. See [`SECURITY.md`](SECURITY.md#read-only-guarantee-architecture-declaration-proof) for the guarantee and its limits.
75
75
 
76
- It gives the agent fourteen typed tools that return frozen Pydantic schemas (output contract 2: one object per tool, one `note`, units in the field names; see [`docs/CONTRACT.md`](docs/CONTRACT.md)), identical whether the server talks to a real robot or to its built-in mock fixtures. Ask why `nav_planner` gets no scan, and the agent reads the bus, finds the BEST_EFFORT writer facing a RELIABLE reader and names the incompatible policy (see [`examples/02-debug-qos-mismatch.md`](examples/02-debug-qos-mismatch.md)). It is meant for ROS2 developers, robotics ML/CV engineers and teams that cannot accept a write path into a production stack.
76
+ It gives the agent fifteen typed tools that return frozen Pydantic schemas (output contract 2: one object per tool, one `note`, units in the field names; see [`docs/CONTRACT.md`](docs/CONTRACT.md)), identical whether the server talks to a real robot or to its built-in mock fixtures. Ask why `nav_planner` gets no scan, and the agent reads the bus, finds the BEST_EFFORT writer facing a RELIABLE reader and names the incompatible policy (see [`examples/02-debug-qos-mismatch.md`](examples/02-debug-qos-mismatch.md)). It is meant for ROS2 developers, robotics ML/CV engineers and teams that cannot accept a write path into a production stack.
77
77
 
78
- For DDS, TopicForge joins a domain as a read-only participant through one open-source binding (Eclipse CycloneDDS from PyPI) and reads the builtin discovery topics that the OMG DDS-RTPS protocol standardizes. So far the author has observed Cyclone DDS and Dust DDS participants on a live bus. RTI Connext, OpenDDS, CoreDX and Fast DDS announce themselves through the same standard discovery, but none of them has been observed yet. This covers discovery only: participants, readers, writers and their QoS. See [`docs/dds-interop-matrix.md`](docs/dds-interop-matrix.md).
78
+ For DDS, TopicForge joins a domain as a read-only participant through one open-source binding (Eclipse CycloneDDS from PyPI) and reads the builtin discovery topics that the OMG DDS-RTPS protocol standardizes. Cyclone DDS, Fast DDS and Dust DDS participants have been observed on live buses: the Fast DDS ones on every CI run of the ROS 2 test bench (Humble and Jazzy with `rmw_fastrtps_cpp`) and in the OmniSim validation. RTI Connext, OpenDDS and CoreDX announce themselves through the same standard discovery, but none of them has been observed yet. This covers discovery only: participants, readers, writers and their QoS. See [`docs/dds-interop-matrix.md`](docs/dds-interop-matrix.md).
79
79
 
80
80
  ## Quickstart
81
81
 
@@ -103,7 +103,7 @@ The server speaks MCP over stdio and waits for a client, so wire it into one. Fo
103
103
 
104
104
  Then ask it to list the topics or to analyze `/tmp/demo.mcap`. For Claude Code: `claude mcp add topicforge -- topicforge`. If the client cannot launch the server (WSL2 to Windows, a robot over an SSH tunnel), `topicforge --transport streamable-http --port 8765` serves `http://127.0.0.1:8765/mcp` on loopback only; see [`docs/CLIENTS.md`](docs/CLIENTS.md#local-http-transport).
105
105
 
106
- **Other MCP clients.** Ready-to-paste configs for Claude Desktop, Cursor, VS Code, Windsurf, Cline, Roo Code, Continue, Zed, JetBrains, Codex, Gemini CLI, Goose and more are in [`docs/CLIENTS.md`](docs/CLIENTS.md). One-click: [Add to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMCIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0%3D) | [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.0%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D).
106
+ **Other MCP clients.** Ready-to-paste configs for Claude Desktop, Cursor, VS Code, Windsurf, Cline, Roo Code, Continue, Zed, JetBrains, Codex, Gemini CLI, Goose and more are in [`docs/CLIENTS.md`](docs/CLIENTS.md). One-click: [Add to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMiIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0%3D) | [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D).
107
107
 
108
108
  Setup for a real ROS2 environment (WSL2, Linux, Docker, native Windows) is in [`docs/TESTING.md`](docs/TESTING.md); recurring monitoring prompts and the privacy contract are in [`docs/TUTORIEL.md`](docs/TUTORIEL.md).
109
109
 
@@ -118,6 +118,7 @@ Every response except `health_check` carries `mode_effective` (`"live"` or `"moc
118
118
  | `get_topic_info` | Message type, publisher/subscriber counts and QoS for one topic |
119
119
  | `list_nodes` | ROS 2 nodes on the graph: names, namespaces, duplicate names (one `ros2 node list` call) |
120
120
  | `get_node_info` | One node's publishers, subscribers, services, actions, parameters (secrets masked) and `use_sim_time`; a node that does not answer is reported, not an error |
121
+ | `inspect_tf` | The TF tree from `/tf_static` and `/tf`: roots, stale and two-parent frames, disconnected trees, sim-time-safe ages and rates, optional path between two frames |
121
122
  | `sample_messages` | Peek recent messages on a ROS2 topic (count capped at 50) |
122
123
  | `analyze_bag` | Summarize a `.mcap` / `.db3` recording or `rosbag2_*` directory (via `ros2 bag info`) |
123
124
  | `list_participants` | DDS participants on the domain: vendor, `name` (EntityName QoS, Cyclone) and `hostname` |
@@ -150,7 +151,7 @@ pip install "topicforge[dds]" # alias, kept so older commands
150
151
  TOPICFORGE_DDS_BACKEND=cyclone python -m topicforge
151
152
  ```
152
153
 
153
- `TOPICFORGE_DDS_BACKEND` accepts `mock` (default), `cyclone`, `fast` and `auto` (`fast`, then `cyclone`, then `mock`, whichever binding imports). The default `mock` selects no DDS backend: installing the Cyclone binding is not enough, you must also set `TOPICFORGE_DDS_BACKEND=cyclone`. With `TOPICFORGE_MODE=live` and no backend selected, the DDS tools raise `DDS module is not active: ...` with the actual cause (backend not selected, binding not installed, or binding installed but the adapter failed to start), and `health_check` reports `dds_backend: "none"` plus `dds_inactive_note`. An explicit value is honoured with or without `ros2` on PATH, in any mode except `mock`. If the binding is missing or the participant cannot start, the server logs a warning naming the cause and falls back to the ROS2 CLI alone, or to the mock fixtures. When both `ros2` and a DDS backend are up, a composite adapter routes the six `ros2` CLI tools (`list_topics`, `get_topic_info`, `list_nodes`, `get_node_info`, `sample_messages`, `analyze_bag`) to the CLI and the six DDS tools to the DDS backend; `peek_bag_samples` reads bags without the CLI.
154
+ `TOPICFORGE_DDS_BACKEND` accepts `mock` (default), `cyclone`, `fast` and `auto` (`fast`, then `cyclone`, then `mock`, whichever binding imports). The default `mock` selects no DDS backend: installing the Cyclone binding is not enough, you must also set `TOPICFORGE_DDS_BACKEND=cyclone`. With `TOPICFORGE_MODE=live` and no backend selected, the DDS tools raise `DDS module is not active: ...` with the actual cause (backend not selected, binding not installed, or binding installed but the adapter failed to start), and `health_check` reports `dds_backend: "none"` plus `dds_inactive_note`. An explicit value is honoured with or without `ros2` on PATH, in any mode except `mock`. If the binding is missing or the participant cannot start, the server logs a warning naming the cause and falls back to the ROS2 CLI alone, or to the mock fixtures. When both `ros2` and a DDS backend are up, a composite adapter routes the seven `ros2` CLI tools (`list_topics`, `get_topic_info`, `list_nodes`, `get_node_info`, `inspect_tf`, `sample_messages`, `analyze_bag`) to the CLI and the six DDS tools to the DDS backend; `peek_bag_samples` reads bags without the CLI.
154
155
 
155
156
  A Fast DDS adapter exists but has never run against a bus, and its `fastdds` Python binding is not on PyPI: build it from eProsima's sources and install it next to TopicForge. There is no `[dds-fast]` extra. Any other value (`rti`, `opensplice`, `coredx`, `intercom`, `opendds`, `dust`) is rejected at startup with an error that lists the valid ones; Cyclone already sees those vendors' participants through standard discovery. Full backend selection, the routing table and the QoS mismatch scenario are in [`docs/DDS_QUICKSTART.md`](docs/DDS_QUICKSTART.md); error messages are in [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md).
156
157
 
@@ -174,7 +175,7 @@ Samples with comments are in [`.env.example`](.env.example). Any invalid value s
174
175
 
175
176
  External validation against a simulated robot's ground truth (OmniSim): [docs/VALIDATION.md](docs/VALIDATION.md).
176
177
 
177
- - DDS validation is partial. The Cyclone adapter has run against a real bus, with Cyclone and Dust DDS participants, on Windows and in CI on Ubuntu and Windows (`.github/workflows/demo.yml`). The Fast DDS adapter has never run against a bus, and no RTI, OpenDDS, CoreDX or OpenSplice participant has been observed by this project. The multi-vendor claim rests on the RTPS protocol guarantee, not on a recorded cross-vendor run.
178
+ - DDS validation is partial. The Cyclone adapter has run against real buses with Cyclone, Fast DDS and Dust DDS participants, on Windows and in CI on Ubuntu and Windows (`.github/workflows/demo.yml`, `.github/workflows/ros2-live.yml`). The Fast DDS adapter (TopicForge joining through the `fastdds` binding) has never run against a bus, and no RTI, OpenDDS, CoreDX or OpenSplice participant has been observed by this project. The multi-vendor claim rests on the RTPS protocol guarantee, not on a recorded cross-vendor run.
178
179
  - User-topic payloads are not decoded. `peek_dds_samples` on a user topic returns count 0 and a note that the topic is announced on the bus; no traffic is read. `topic_metrics` therefore has data only for the builtin discovery topics and says so in its `status`. It is a discovery-layer probe, not a publish-rate monitor.
179
180
  - Liveliness at runtime is not observed. A writer that is alive but silent (a hung process whose lease is still renewed) looks healthy, because TopicForge reads discovery, not data. An opt-in data probe is planned. A crash and a clean leave cannot be told apart, and `lost_ns` is an upper bound of the death.
180
181
  - Cyclone vendor ids: participants that do not follow the RTPS vendor-id convention in their GUID prefix (Dust DDS, and RTI by default) are reported with vendor `unknown`.
@@ -202,10 +203,10 @@ When on, each tool call emits one event with exactly six fields:
202
203
 
203
204
  | Field | Example | Notes |
204
205
  | ------------ | --------------- | ----------------------------------------------------------- |
205
- | `tool_name` | `"list_topics"` | One of the fourteen tools, never argument values |
206
+ | `tool_name` | `"list_topics"` | One of the fifteen tools, never argument values |
206
207
  | `latency_ms` | `12.34` | Handler wall-clock duration, 2 decimals |
207
208
  | `mode` | `"mock"` | Mode of the adapter actually serving: `mock` or `live` |
208
- | `version` | `"0.7.0"` | TopicForge server version |
209
+ | `version` | `"0.7.2"` | TopicForge server version |
209
210
  | `session_id` | `"a1b2c3..."` | Random UUID per process, never persisted |
210
211
  | `success` | `true` | Whether the handler returned or raised |
211
212
 
@@ -237,7 +238,7 @@ Tests run against the mock adapter, the live adapter's pure parsers and the bind
237
238
 
238
239
  ## Upgrading
239
240
 
240
- TopicForge is pre-1.0; [`CHANGELOG.md`](CHANGELOG.md) lists every change, including the yanked releases and removed extras. 0.7.0 changes the shape of tool results (`contract_version` 2): [`docs/MIGRATION-0.7.md`](docs/MIGRATION-0.7.md) maps every old field to its new one.
241
+ TopicForge is pre-1.0; [`CHANGELOG.md`](CHANGELOG.md) lists every change, including the yanked releases and removed extras. 0.7.0 changed the shape of tool results (`contract_version` 2): [`docs/MIGRATION-0.7.md`](docs/MIGRATION-0.7.md) maps every old field to its new one.
241
242
 
242
243
  ## Layout
243
244
 
@@ -12,9 +12,9 @@ A read-only MCP (Model Context Protocol) server that lets an AI agent inspect a
12
12
 
13
13
  Every tool also declares itself read-only in the MCP protocol (`readOnlyHint`, `destructiveHint=false`, `idempotentHint`, with an honest `openWorldHint`), and a test fails if any tool lacks it. See [`SECURITY.md`](SECURITY.md#read-only-guarantee-architecture-declaration-proof) for the guarantee and its limits.
14
14
 
15
- It gives the agent fourteen typed tools that return frozen Pydantic schemas (output contract 2: one object per tool, one `note`, units in the field names; see [`docs/CONTRACT.md`](docs/CONTRACT.md)), identical whether the server talks to a real robot or to its built-in mock fixtures. Ask why `nav_planner` gets no scan, and the agent reads the bus, finds the BEST_EFFORT writer facing a RELIABLE reader and names the incompatible policy (see [`examples/02-debug-qos-mismatch.md`](examples/02-debug-qos-mismatch.md)). It is meant for ROS2 developers, robotics ML/CV engineers and teams that cannot accept a write path into a production stack.
15
+ It gives the agent fifteen typed tools that return frozen Pydantic schemas (output contract 2: one object per tool, one `note`, units in the field names; see [`docs/CONTRACT.md`](docs/CONTRACT.md)), identical whether the server talks to a real robot or to its built-in mock fixtures. Ask why `nav_planner` gets no scan, and the agent reads the bus, finds the BEST_EFFORT writer facing a RELIABLE reader and names the incompatible policy (see [`examples/02-debug-qos-mismatch.md`](examples/02-debug-qos-mismatch.md)). It is meant for ROS2 developers, robotics ML/CV engineers and teams that cannot accept a write path into a production stack.
16
16
 
17
- For DDS, TopicForge joins a domain as a read-only participant through one open-source binding (Eclipse CycloneDDS from PyPI) and reads the builtin discovery topics that the OMG DDS-RTPS protocol standardizes. So far the author has observed Cyclone DDS and Dust DDS participants on a live bus. RTI Connext, OpenDDS, CoreDX and Fast DDS announce themselves through the same standard discovery, but none of them has been observed yet. This covers discovery only: participants, readers, writers and their QoS. See [`docs/dds-interop-matrix.md`](docs/dds-interop-matrix.md).
17
+ For DDS, TopicForge joins a domain as a read-only participant through one open-source binding (Eclipse CycloneDDS from PyPI) and reads the builtin discovery topics that the OMG DDS-RTPS protocol standardizes. Cyclone DDS, Fast DDS and Dust DDS participants have been observed on live buses: the Fast DDS ones on every CI run of the ROS 2 test bench (Humble and Jazzy with `rmw_fastrtps_cpp`) and in the OmniSim validation. RTI Connext, OpenDDS and CoreDX announce themselves through the same standard discovery, but none of them has been observed yet. This covers discovery only: participants, readers, writers and their QoS. See [`docs/dds-interop-matrix.md`](docs/dds-interop-matrix.md).
18
18
 
19
19
  ## Quickstart
20
20
 
@@ -42,7 +42,7 @@ The server speaks MCP over stdio and waits for a client, so wire it into one. Fo
42
42
 
43
43
  Then ask it to list the topics or to analyze `/tmp/demo.mcap`. For Claude Code: `claude mcp add topicforge -- topicforge`. If the client cannot launch the server (WSL2 to Windows, a robot over an SSH tunnel), `topicforge --transport streamable-http --port 8765` serves `http://127.0.0.1:8765/mcp` on loopback only; see [`docs/CLIENTS.md`](docs/CLIENTS.md#local-http-transport).
44
44
 
45
- **Other MCP clients.** Ready-to-paste configs for Claude Desktop, Cursor, VS Code, Windsurf, Cline, Roo Code, Continue, Zed, JetBrains, Codex, Gemini CLI, Goose and more are in [`docs/CLIENTS.md`](docs/CLIENTS.md). One-click: [Add to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMCIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0%3D) | [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.0%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D).
45
+ **Other MCP clients.** Ready-to-paste configs for Claude Desktop, Cursor, VS Code, Windsurf, Cline, Roo Code, Continue, Zed, JetBrains, Codex, Gemini CLI, Goose and more are in [`docs/CLIENTS.md`](docs/CLIENTS.md). One-click: [Add to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMiIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0%3D) | [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D).
46
46
 
47
47
  Setup for a real ROS2 environment (WSL2, Linux, Docker, native Windows) is in [`docs/TESTING.md`](docs/TESTING.md); recurring monitoring prompts and the privacy contract are in [`docs/TUTORIEL.md`](docs/TUTORIEL.md).
48
48
 
@@ -57,6 +57,7 @@ Every response except `health_check` carries `mode_effective` (`"live"` or `"moc
57
57
  | `get_topic_info` | Message type, publisher/subscriber counts and QoS for one topic |
58
58
  | `list_nodes` | ROS 2 nodes on the graph: names, namespaces, duplicate names (one `ros2 node list` call) |
59
59
  | `get_node_info` | One node's publishers, subscribers, services, actions, parameters (secrets masked) and `use_sim_time`; a node that does not answer is reported, not an error |
60
+ | `inspect_tf` | The TF tree from `/tf_static` and `/tf`: roots, stale and two-parent frames, disconnected trees, sim-time-safe ages and rates, optional path between two frames |
60
61
  | `sample_messages` | Peek recent messages on a ROS2 topic (count capped at 50) |
61
62
  | `analyze_bag` | Summarize a `.mcap` / `.db3` recording or `rosbag2_*` directory (via `ros2 bag info`) |
62
63
  | `list_participants` | DDS participants on the domain: vendor, `name` (EntityName QoS, Cyclone) and `hostname` |
@@ -89,7 +90,7 @@ pip install "topicforge[dds]" # alias, kept so older commands
89
90
  TOPICFORGE_DDS_BACKEND=cyclone python -m topicforge
90
91
  ```
91
92
 
92
- `TOPICFORGE_DDS_BACKEND` accepts `mock` (default), `cyclone`, `fast` and `auto` (`fast`, then `cyclone`, then `mock`, whichever binding imports). The default `mock` selects no DDS backend: installing the Cyclone binding is not enough, you must also set `TOPICFORGE_DDS_BACKEND=cyclone`. With `TOPICFORGE_MODE=live` and no backend selected, the DDS tools raise `DDS module is not active: ...` with the actual cause (backend not selected, binding not installed, or binding installed but the adapter failed to start), and `health_check` reports `dds_backend: "none"` plus `dds_inactive_note`. An explicit value is honoured with or without `ros2` on PATH, in any mode except `mock`. If the binding is missing or the participant cannot start, the server logs a warning naming the cause and falls back to the ROS2 CLI alone, or to the mock fixtures. When both `ros2` and a DDS backend are up, a composite adapter routes the six `ros2` CLI tools (`list_topics`, `get_topic_info`, `list_nodes`, `get_node_info`, `sample_messages`, `analyze_bag`) to the CLI and the six DDS tools to the DDS backend; `peek_bag_samples` reads bags without the CLI.
93
+ `TOPICFORGE_DDS_BACKEND` accepts `mock` (default), `cyclone`, `fast` and `auto` (`fast`, then `cyclone`, then `mock`, whichever binding imports). The default `mock` selects no DDS backend: installing the Cyclone binding is not enough, you must also set `TOPICFORGE_DDS_BACKEND=cyclone`. With `TOPICFORGE_MODE=live` and no backend selected, the DDS tools raise `DDS module is not active: ...` with the actual cause (backend not selected, binding not installed, or binding installed but the adapter failed to start), and `health_check` reports `dds_backend: "none"` plus `dds_inactive_note`. An explicit value is honoured with or without `ros2` on PATH, in any mode except `mock`. If the binding is missing or the participant cannot start, the server logs a warning naming the cause and falls back to the ROS2 CLI alone, or to the mock fixtures. When both `ros2` and a DDS backend are up, a composite adapter routes the seven `ros2` CLI tools (`list_topics`, `get_topic_info`, `list_nodes`, `get_node_info`, `inspect_tf`, `sample_messages`, `analyze_bag`) to the CLI and the six DDS tools to the DDS backend; `peek_bag_samples` reads bags without the CLI.
93
94
 
94
95
  A Fast DDS adapter exists but has never run against a bus, and its `fastdds` Python binding is not on PyPI: build it from eProsima's sources and install it next to TopicForge. There is no `[dds-fast]` extra. Any other value (`rti`, `opensplice`, `coredx`, `intercom`, `opendds`, `dust`) is rejected at startup with an error that lists the valid ones; Cyclone already sees those vendors' participants through standard discovery. Full backend selection, the routing table and the QoS mismatch scenario are in [`docs/DDS_QUICKSTART.md`](docs/DDS_QUICKSTART.md); error messages are in [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md).
95
96
 
@@ -113,7 +114,7 @@ Samples with comments are in [`.env.example`](.env.example). Any invalid value s
113
114
 
114
115
  External validation against a simulated robot's ground truth (OmniSim): [docs/VALIDATION.md](docs/VALIDATION.md).
115
116
 
116
- - DDS validation is partial. The Cyclone adapter has run against a real bus, with Cyclone and Dust DDS participants, on Windows and in CI on Ubuntu and Windows (`.github/workflows/demo.yml`). The Fast DDS adapter has never run against a bus, and no RTI, OpenDDS, CoreDX or OpenSplice participant has been observed by this project. The multi-vendor claim rests on the RTPS protocol guarantee, not on a recorded cross-vendor run.
117
+ - DDS validation is partial. The Cyclone adapter has run against real buses with Cyclone, Fast DDS and Dust DDS participants, on Windows and in CI on Ubuntu and Windows (`.github/workflows/demo.yml`, `.github/workflows/ros2-live.yml`). The Fast DDS adapter (TopicForge joining through the `fastdds` binding) has never run against a bus, and no RTI, OpenDDS, CoreDX or OpenSplice participant has been observed by this project. The multi-vendor claim rests on the RTPS protocol guarantee, not on a recorded cross-vendor run.
117
118
  - User-topic payloads are not decoded. `peek_dds_samples` on a user topic returns count 0 and a note that the topic is announced on the bus; no traffic is read. `topic_metrics` therefore has data only for the builtin discovery topics and says so in its `status`. It is a discovery-layer probe, not a publish-rate monitor.
118
119
  - Liveliness at runtime is not observed. A writer that is alive but silent (a hung process whose lease is still renewed) looks healthy, because TopicForge reads discovery, not data. An opt-in data probe is planned. A crash and a clean leave cannot be told apart, and `lost_ns` is an upper bound of the death.
119
120
  - Cyclone vendor ids: participants that do not follow the RTPS vendor-id convention in their GUID prefix (Dust DDS, and RTI by default) are reported with vendor `unknown`.
@@ -141,10 +142,10 @@ When on, each tool call emits one event with exactly six fields:
141
142
 
142
143
  | Field | Example | Notes |
143
144
  | ------------ | --------------- | ----------------------------------------------------------- |
144
- | `tool_name` | `"list_topics"` | One of the fourteen tools, never argument values |
145
+ | `tool_name` | `"list_topics"` | One of the fifteen tools, never argument values |
145
146
  | `latency_ms` | `12.34` | Handler wall-clock duration, 2 decimals |
146
147
  | `mode` | `"mock"` | Mode of the adapter actually serving: `mock` or `live` |
147
- | `version` | `"0.7.0"` | TopicForge server version |
148
+ | `version` | `"0.7.2"` | TopicForge server version |
148
149
  | `session_id` | `"a1b2c3..."` | Random UUID per process, never persisted |
149
150
  | `success` | `true` | Whether the handler returned or raised |
150
151
 
@@ -176,7 +177,7 @@ Tests run against the mock adapter, the live adapter's pure parsers and the bind
176
177
 
177
178
  ## Upgrading
178
179
 
179
- TopicForge is pre-1.0; [`CHANGELOG.md`](CHANGELOG.md) lists every change, including the yanked releases and removed extras. 0.7.0 changes the shape of tool results (`contract_version` 2): [`docs/MIGRATION-0.7.md`](docs/MIGRATION-0.7.md) maps every old field to its new one.
180
+ TopicForge is pre-1.0; [`CHANGELOG.md`](CHANGELOG.md) lists every change, including the yanked releases and removed extras. 0.7.0 changed the shape of tool results (`contract_version` 2): [`docs/MIGRATION-0.7.md`](docs/MIGRATION-0.7.md) maps every old field to its new one.
180
181
 
181
182
  ## Layout
182
183
 
@@ -6,7 +6,7 @@ TopicForge (ROS 2 / DDS) is a local, read-only MCP server that speaks stdio.
6
6
  Every client below launches it as a child process with the same command:
7
7
 
8
8
  ```
9
- uvx --from "topicforge==0.7.0" topicforge
9
+ uvx --from "topicforge==0.7.2" topicforge
10
10
  ```
11
11
 
12
12
  and the same three environment variables:
@@ -21,7 +21,7 @@ The registry name is `io.github.yaniswav/topicforge`. Where a client asks for a
21
21
  display name, use **TopicForge (ROS 2 / DDS)**: an unrelated SEO product is also
22
22
  called TopicForge in the MCP registries.
23
23
 
24
- The version pin (`==0.7.0`) is moved on every release together with the other
24
+ The version pin (`==0.7.2`) is moved on every release together with the other
25
25
  version strings; a test keeps them in sync.
26
26
 
27
27
  ## Before you start
@@ -44,7 +44,7 @@ version strings; a test keeps them in sync.
44
44
  `"--from"` in the args. To build the binding yourself, install the Cyclone C library and
45
45
  run `pip install "topicforge[dds]"`. The `[dds]` and `[dds-cyclone]` extras still work
46
46
  as aliases, so older commands keep installing.
47
- - **pip alternative.** `pip install "topicforge==0.7.0"`, then use
47
+ - **pip alternative.** `pip install "topicforge==0.7.2"`, then use
48
48
  `"command": "topicforge"` (or `"command": "python", "args": ["-m", "topicforge"]`)
49
49
  with no `args` for uvx. Use the absolute path of the binary if the client does
50
50
  not see your venv.
@@ -72,7 +72,7 @@ say where the file lives and what differs.
72
72
  "mcpServers": {
73
73
  "topicforge": {
74
74
  "command": "uvx",
75
- "args": ["--from", "topicforge==0.7.0", "topicforge"],
75
+ "args": ["--from", "topicforge==0.7.2", "topicforge"],
76
76
  "env": {
77
77
  "TOPICFORGE_MODE": "auto",
78
78
  "TOPICFORGE_DDS_BACKEND": "cyclone",
@@ -95,7 +95,7 @@ claude plugin install topicforge@topicforge
95
95
  Or just the server:
96
96
 
97
97
  ```
98
- claude mcp add topicforge --env TOPICFORGE_MODE=auto --env TOPICFORGE_DDS_BACKEND=cyclone --env TOPICFORGE_DDS_DOMAIN_ID=0 -- uvx --from "topicforge==0.7.0" topicforge
98
+ claude mcp add topicforge --env TOPICFORGE_MODE=auto --env TOPICFORGE_DDS_BACKEND=cyclone --env TOPICFORGE_DDS_DOMAIN_ID=0 -- uvx --from "topicforge==0.7.2" topicforge
99
99
  ```
100
100
 
101
101
  ## Claude Desktop
@@ -112,9 +112,9 @@ the common JSON shape above and restart the app completely. On Windows, if
112
112
 
113
113
  The one-click links in this page and in the README are https redirects, because GitHub and PyPI strip `cursor://` and `vscode:` links. Only the raw schemes are documented by Cursor and VS Code; the https forms (`cursor.com/install-mcp`, `vscode.dev/redirect/mcp/install`) were observed to redirect correctly on 2026-10-06 but are not in the vendors' docs (unverified, last checked 2026-10-06). The raw links are given as a fallback.
114
114
 
115
- One click: [Add TopicForge to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMCIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0%3D)
115
+ One click: [Add TopicForge to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMiIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0%3D)
116
116
 
117
- If that page does not open Cursor, use the raw deeplink: `cursor://anysphere.cursor-deeplink/mcp/install?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMCIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0=`
117
+ If that page does not open Cursor, use the raw deeplink: `cursor://anysphere.cursor-deeplink/mcp/install?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlPT0wLjcuMiIsInRvcGljZm9yZ2UiXSwiZW52Ijp7IlRPUElDRk9SR0VfTU9ERSI6ImF1dG8iLCJUT1BJQ0ZPUkdFX0REU19CQUNLRU5EIjoiY3ljbG9uZSIsIlRPUElDRk9SR0VfRERTX0RPTUFJTl9JRCI6IjAifX0%3D`
118
118
 
119
119
  Or paste the common JSON shape into `~/.cursor/mcp.json` (all projects) or
120
120
  `.cursor/mcp.json` (one project).
@@ -125,9 +125,9 @@ The `plugin/` folder of this repository is also an [Agent Plugins](https://agent
125
125
 
126
126
  ## VS Code / GitHub Copilot
127
127
 
128
- One click: [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.0%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D)
128
+ One click: [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D)
129
129
 
130
- Fallback, the raw URL handler: `vscode:mcp/install?%7B%22name%22%3A%22topicforge%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.0%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D`
130
+ Fallback, the raw URL handler: `vscode:mcp/install?%7B%22name%22%3A%22topicforge%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%3D%3D0.7.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D`
131
131
 
132
132
  Or put this in `.vscode/mcp.json` (the key is `servers`, not `mcpServers`), or run
133
133
  "MCP: Add Server" from the Command Palette:
@@ -138,7 +138,7 @@ Or put this in `.vscode/mcp.json` (the key is `servers`, not `mcpServers`), or r
138
138
  "topicforge": {
139
139
  "type": "stdio",
140
140
  "command": "uvx",
141
- "args": ["--from", "topicforge==0.7.0", "topicforge"],
141
+ "args": ["--from", "topicforge==0.7.2", "topicforge"],
142
142
  "env": {
143
143
  "TOPICFORGE_MODE": "auto",
144
144
  "TOPICFORGE_DDS_BACKEND": "cyclone",
@@ -167,7 +167,7 @@ Servers", and paste the common JSON shape (the file is
167
167
  Project file `.roo/mcp.json` (takes precedence) or the global `mcp_settings.json`
168
168
  opened from the MCP view. Paste the common JSON shape. Roo's docs say Windows
169
169
  needs a `cmd /c` wrapper for `npx`; for `uvx`, try it directly first and fall back
170
- to `"command": "cmd", "args": ["/c", "uvx", "--from", "topicforge==0.7.0",
170
+ to `"command": "cmd", "args": ["/c", "uvx", "--from", "topicforge==0.7.2",
171
171
  "topicforge"]` if it fails to start.
172
172
 
173
173
  ## Continue
@@ -184,7 +184,7 @@ mcpServers:
184
184
  command: uvx
185
185
  args:
186
186
  - "--from"
187
- - "topicforge==0.7.0"
187
+ - "topicforge==0.7.2"
188
188
  - "topicforge"
189
189
  env:
190
190
  TOPICFORGE_MODE: auto
@@ -201,7 +201,7 @@ In `settings.json`, under `context_servers`:
201
201
  "context_servers": {
202
202
  "topicforge": {
203
203
  "command": "uvx",
204
- "args": ["--from", "topicforge==0.7.0", "topicforge"],
204
+ "args": ["--from", "topicforge==0.7.2", "topicforge"],
205
205
  "env": {
206
206
  "TOPICFORGE_MODE": "auto",
207
207
  "TOPICFORGE_DDS_BACKEND": "cyclone",
@@ -227,7 +227,7 @@ run with the dds extra can exceed, so set it to 60 s:
227
227
  ```toml
228
228
  [mcp_servers.topicforge]
229
229
  command = "uvx"
230
- args = ["--from", "topicforge==0.7.0", "topicforge"]
230
+ args = ["--from", "topicforge==0.7.2", "topicforge"]
231
231
  startup_timeout_sec = 60
232
232
 
233
233
  [mcp_servers.topicforge.env]
@@ -258,7 +258,7 @@ extensions:
258
258
  name: TopicForge (ROS 2 / DDS)
259
259
  type: stdio
260
260
  cmd: uvx
261
- args: [--from, "topicforge==0.7.0", topicforge]
261
+ args: [--from, "topicforge==0.7.2", topicforge]
262
262
  enabled: true
263
263
  envs: { "TOPICFORGE_MODE": "auto", "TOPICFORGE_DDS_BACKEND": "cyclone", "TOPICFORGE_DDS_DOMAIN_ID": "0" }
264
264
  timeout: 300
@@ -269,7 +269,7 @@ extensions:
269
269
  Program tab > Install > Edit `mcp.json` (same notation as Cursor), then paste the
270
270
  common JSON shape. LM Studio's docs only show remote examples; local command
271
271
  servers follow the Cursor notation but are not documented explicitly. Small
272
- local models may struggle with fourteen tools.
272
+ local models may struggle with fifteen tools.
273
273
 
274
274
  ## Amazon Q Developer / Kiro
275
275
 
@@ -325,7 +325,7 @@ when the question matches.
325
325
 
326
326
  ## Troubleshooting
327
327
 
328
- - Run the command by hand first: `uvx --from "topicforge==0.7.0" topicforge --version`.
328
+ - Run the command by hand first: `uvx --from "topicforge==0.7.2" topicforge --version`.
329
329
  - Server starts but sees no DDS participants: check the domain id, and that the
330
330
  client machine is on the same network as the robot (DDS discovery uses
331
331
  multicast UDP). Ask the assistant to call `health_check`.