xdog-coding 2.4.1__tar.gz → 2.4.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 (427) hide show
  1. xdog_coding-2.4.2/PKG-INFO +2624 -0
  2. xdog_coding-2.4.2/README.md +2594 -0
  3. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/pyproject.toml +8 -4
  4. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/__init__.py +1 -1
  5. xdog_coding-2.4.2/src/xdog/coding/acp/__init__.py +1 -0
  6. xdog_coding-2.4.2/src/xdog/coding/acp/backend.py +354 -0
  7. xdog_coding-2.4.2/src/xdog/coding/acp/bridge.py +12 -0
  8. xdog_coding-2.4.2/src/xdog/coding/acp/cli.py +15 -0
  9. xdog_coding-2.4.2/src/xdog/coding/acp/client.py +80 -0
  10. xdog_coding-2.4.2/src/xdog/coding/acp/extensions.py +5 -0
  11. xdog_coding-2.4.2/src/xdog/coding/acp/ingress.py +195 -0
  12. xdog_coding-2.4.2/src/xdog/coding/acp/ingress_backend.py +232 -0
  13. xdog_coding-2.4.2/src/xdog/coding/acp/ingress_main.py +39 -0
  14. xdog_coding-2.4.2/src/xdog/coding/acp/server.py +92 -0
  15. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/cli/args.py +34 -10
  16. xdog_coding-2.4.2/src/xdog/coding/cli/enqueue.py +16 -0
  17. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/config.py +45 -2
  18. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/agent_session.py +347 -95
  19. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/child_agents.py +9 -38
  20. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/context_messages.py +5 -10
  21. xdog_coding-2.4.2/src/xdog/coding/core/inbox_commands.py +93 -0
  22. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/navigation.py +1 -1
  23. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/permissions.py +28 -15
  24. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/prompt_templates.py +15 -0
  25. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/sdk.py +82 -42
  26. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/session_manager.py +17 -8
  27. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/session_staging.py +4 -4
  28. xdog_coding-2.4.2/src/xdog/coding/core/sessions/__init__.py +1 -0
  29. xdog_coding-2.4.2/src/xdog/coding/core/sessions/availability.py +15 -0
  30. xdog_coding-2.4.2/src/xdog/coding/core/sessions/batches.py +103 -0
  31. xdog_coding-2.4.2/src/xdog/coding/core/sessions/controller.py +713 -0
  32. xdog_coding-2.4.2/src/xdog/coding/core/sessions/inbox_models.py +195 -0
  33. xdog_coding-2.4.2/src/xdog/coding/core/sessions/inbox_runtime.py +424 -0
  34. xdog_coding-2.4.2/src/xdog/coding/core/sessions/inbox_store.py +438 -0
  35. xdog_coding-2.4.2/src/xdog/coding/core/sessions/inbox_views.py +39 -0
  36. xdog_coding-2.4.2/src/xdog/coding/core/sessions/intake.py +21 -0
  37. xdog_coding-2.4.2/src/xdog/coding/core/sessions/models.py +50 -0
  38. xdog_coding-2.4.2/src/xdog/coding/core/sessions/operations.py +28 -0
  39. xdog_coding-2.4.2/src/xdog/coding/core/sessions/ownership.py +143 -0
  40. xdog_coding-2.4.2/src/xdog/coding/core/sessions/router.py +38 -0
  41. xdog_coding-2.4.2/src/xdog/coding/core/sessions/runtime.py +178 -0
  42. xdog_coding-2.4.2/src/xdog/coding/core/sessions/store.py +151 -0
  43. xdog_coding-2.4.2/src/xdog/coding/core/sessions/turns.py +56 -0
  44. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/settings_manager.py +22 -1
  45. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/slash_commands.py +13 -16
  46. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/system_prompt.py +15 -0
  47. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/transcript_source.py +1 -1
  48. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/main.py +37 -26
  49. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/chat_log.py +30 -0
  50. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/custom_editor.py +1 -1
  51. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/interactive_mode.py +349 -1832
  52. xdog_coding-2.4.2/src/xdog/coding/modes/interactive/session_events.py +358 -0
  53. xdog_coding-2.4.2/src/xdog/coding/modes/interactive/session_presenter.py +284 -0
  54. xdog_coding-2.4.2/tests/acp_owner_agent.py +46 -0
  55. xdog_coding-2.4.2/tests/batch_helpers.py +15 -0
  56. xdog_coding-2.4.2/tests/conftest.py +26 -0
  57. xdog_coding-2.4.2/tests/extension_session_helpers.py +52 -0
  58. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/fixtures/terminal_client.py +26 -37
  59. xdog_coding-2.4.2/tests/fixtures/terminal_review.py +25 -0
  60. xdog_coding-2.4.2/tests/session_owner_process.py +14 -0
  61. xdog_coding-2.4.2/tests/test_access_scope.py +228 -0
  62. xdog_coding-2.4.2/tests/test_acp_artifact_contract.py +43 -0
  63. xdog_coding-2.4.2/tests/test_acp_backend.py +129 -0
  64. xdog_coding-2.4.2/tests/test_acp_batch_intake.py +387 -0
  65. xdog_coding-2.4.2/tests/test_acp_bridge.py +93 -0
  66. xdog_coding-2.4.2/tests/test_acp_cli.py +22 -0
  67. xdog_coding-2.4.2/tests/test_acp_enqueue_cli.py +116 -0
  68. xdog_coding-2.4.2/tests/test_acp_ingress.py +212 -0
  69. xdog_coding-2.4.2/tests/test_acp_ingress_lifecycle.py +213 -0
  70. xdog_coding-2.4.2/tests/test_acp_offline_inbox.py +172 -0
  71. xdog_coding-2.4.2/tests/test_acp_optional_imports.py +76 -0
  72. xdog_coding-2.4.2/tests/test_acp_review_regressions.py +320 -0
  73. xdog_coding-2.4.2/tests/test_active_tool_persistence.py +42 -0
  74. xdog_coding-2.4.2/tests/test_active_tool_retirement.py +46 -0
  75. xdog_coding-2.4.2/tests/test_after_run_compaction.py +14 -0
  76. xdog_coding-2.4.2/tests/test_after_run_name.py +43 -0
  77. xdog_coding-2.4.2/tests/test_batch_config.py +112 -0
  78. xdog_coding-2.4.2/tests/test_batch_display.py +245 -0
  79. xdog_coding-2.4.2/tests/test_batch_mode_errors.py +46 -0
  80. xdog_coding-2.4.2/tests/test_batch_turns.py +253 -0
  81. xdog_coding-2.4.2/tests/test_child_active_tools.py +62 -0
  82. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_child_agents.py +8 -299
  83. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_child_image_admission.py +1 -68
  84. xdog_coding-2.4.2/tests/test_child_image_submission.py +251 -0
  85. xdog_coding-2.4.2/tests/test_child_queue_ui.py +172 -0
  86. xdog_coding-2.4.2/tests/test_command_artifact_export_ui.py +29 -0
  87. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_compact_layout.py +82 -81
  88. xdog_coding-2.4.2/tests/test_compaction_controls_ui.py +98 -0
  89. xdog_coding-2.4.2/tests/test_extension_command_results_ui.py +30 -0
  90. xdog_coding-2.4.2/tests/test_extension_core_readonly.py +162 -0
  91. xdog_coding-2.4.2/tests/test_extension_editor_ui.py +14 -0
  92. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_extension_input_draft_isolation.py +3 -4
  93. xdog_coding-2.4.2/tests/test_extension_input_ui.py +31 -0
  94. xdog_coding-2.4.2/tests/test_extension_navigation_ui.py +24 -0
  95. xdog_coding-2.4.2/tests/test_extension_provider_startup.py +36 -0
  96. xdog_coding-2.4.2/tests/test_extension_readonly_ui.py +185 -0
  97. xdog_coding-2.4.2/tests/test_extension_session_context_ui.py +13 -0
  98. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_image_composer.py +28 -13
  99. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_image_lifecycle_admission.py +9 -7
  100. xdog_coding-2.4.2/tests/test_inbox_activation_navigation.py +74 -0
  101. xdog_coding-2.4.2/tests/test_inbox_auto_consume.py +409 -0
  102. xdog_coding-2.4.2/tests/test_inbox_commands.py +287 -0
  103. xdog_coding-2.4.2/tests/test_inbox_controller.py +448 -0
  104. xdog_coding-2.4.2/tests/test_inbox_crash.py +54 -0
  105. xdog_coding-2.4.2/tests/test_inbox_display.py +379 -0
  106. xdog_coding-2.4.2/tests/test_inbox_store.py +343 -0
  107. xdog_coding-2.4.2/tests/test_inbox_v2.py +283 -0
  108. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_interactive_commands.py +6 -1
  109. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_interactive_mode.py +63 -58
  110. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_live_extensions.py +0 -68
  111. xdog_coding-2.4.2/tests/test_mcp_auth_projection.py +101 -0
  112. xdog_coding-2.4.2/tests/test_mcp_browser.py +123 -0
  113. xdog_coding-2.4.2/tests/test_mcp_catalog_watch_ui.py +32 -0
  114. xdog_coding-2.4.2/tests/test_mcp_combined_watch_ui.py +38 -0
  115. xdog_coding-2.4.2/tests/test_mcp_manual_picker_ui.py +131 -0
  116. xdog_coding-2.4.2/tests/test_mcp_modern_browser_cancel.py +53 -0
  117. xdog_coding-2.4.2/tests/test_mcp_modern_browser_ui.py +149 -0
  118. xdog_coding-2.4.2/tests/test_mcp_retired_gateway.py +31 -0
  119. xdog_coding-2.4.2/tests/test_mcp_roots_review_ui.py +29 -0
  120. xdog_coding-2.4.2/tests/test_mcp_sampling_ui.py +61 -0
  121. xdog_coding-2.4.2/tests/test_mcp_task_terminal.py +145 -0
  122. xdog_coding-2.4.2/tests/test_native_session_queue.py +189 -0
  123. xdog_coding-2.4.2/tests/test_no_coding_rpc.py +84 -0
  124. xdog_coding-2.4.2/tests/test_no_legacy_event_host.py +70 -0
  125. xdog_coding-2.4.2/tests/test_oauth_ui.py +239 -0
  126. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_permissions.py +51 -0
  127. xdog_coding-2.4.2/tests/test_provider_oauth_ui.py +7 -0
  128. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_queue_controls.py +8 -11
  129. xdog_coding-2.4.2/tests/test_readonly_ui.py +217 -0
  130. xdog_coding-2.4.2/tests/test_removed_child_return_ui.py +50 -0
  131. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_rendered_image_context.py +9 -7
  132. xdog_coding-2.4.2/tests/test_renderer_contracts_ui.py +78 -0
  133. xdog_coding-2.4.2/tests/test_repository_review.py +112 -0
  134. xdog_coding-2.4.2/tests/test_retained_history.py +45 -0
  135. xdog_coding-2.4.2/tests/test_runtime_prompt.py +78 -0
  136. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_saved_child_drafts.py +602 -391
  137. xdog_coding-2.4.2/tests/test_saved_source_ui.py +68 -0
  138. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_sdk_session_state.py +6 -0
  139. xdog_coding-2.4.2/tests/test_session_batches.py +503 -0
  140. xdog_coding-2.4.2/tests/test_session_control_fences.py +125 -0
  141. xdog_coding-2.4.2/tests/test_session_controller.py +289 -0
  142. xdog_coding-2.4.2/tests/test_session_history_display.py +183 -0
  143. xdog_coding-2.4.2/tests/test_session_input_store.py +59 -0
  144. xdog_coding-2.4.2/tests/test_session_message_display.py +145 -0
  145. xdog_coding-2.4.2/tests/test_session_mode_routing.py +53 -0
  146. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_session_name_ui.py +5 -5
  147. xdog_coding-2.4.2/tests/test_session_ownership.py +117 -0
  148. xdog_coding-2.4.2/tests/test_session_router.py +22 -0
  149. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_session_smoke.py +2 -11
  150. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_session_staging.py +4 -4
  151. xdog_coding-2.4.2/tests/test_session_turns.py +33 -0
  152. xdog_coding-2.4.2/tests/test_skill_controls_ui.py +33 -0
  153. xdog_coding-2.4.2/tests/test_terminal_acceptance.py +508 -0
  154. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_tui_usability.py +17 -13
  155. xdog_coding-2.4.1/PKG-INFO +0 -4467
  156. xdog_coding-2.4.1/README.md +0 -4439
  157. xdog_coding-2.4.1/src/xdog/coding/modes/interactive/after_run_compaction.py +0 -86
  158. xdog_coding-2.4.1/src/xdog/coding/modes/interactive/after_run_name.py +0 -42
  159. xdog_coding-2.4.1/src/xdog/coding/modes/interactive/after_run_tools.py +0 -54
  160. xdog_coding-2.4.1/src/xdog/coding/modes/interactive/message_inputs.py +0 -68
  161. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/__init__.py +0 -1
  162. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/after_run_compaction.py +0 -119
  163. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/after_run_name.py +0 -95
  164. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/after_run_tools.py +0 -117
  165. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/children.py +0 -1088
  166. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/context_messages.py +0 -130
  167. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/custom_delivery.py +0 -65
  168. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/editor_write.py +0 -73
  169. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/events.py +0 -229
  170. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/extensions.py +0 -1175
  171. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/images.py +0 -65
  172. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/input.py +0 -71
  173. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/navigation.py +0 -230
  174. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/output.py +0 -160
  175. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/parent_drafts.py +0 -338
  176. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/provider_auth.py +0 -54
  177. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/queued_inputs.py +0 -108
  178. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/rpc_mode.py +0 -529
  179. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/terminal.py +0 -141
  180. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/terminal_data.py +0 -43
  181. xdog_coding-2.4.1/src/xdog/coding/modes/rpc/transcripts.py +0 -289
  182. xdog_coding-2.4.1/tests/fixtures/rpc_client.py +0 -98
  183. xdog_coding-2.4.1/tests/fixtures/rpc_menu_client.py +0 -37
  184. xdog_coding-2.4.1/tests/fixtures/rpc_parent_draft_client.py +0 -198
  185. xdog_coding-2.4.1/tests/fixtures/rpc_terminal_client.py +0 -206
  186. xdog_coding-2.4.1/tests/fixtures/rpc_terminal_edit_client.py +0 -185
  187. xdog_coding-2.4.1/tests/test_active_tool_persistence.py +0 -199
  188. xdog_coding-2.4.1/tests/test_active_tool_persistence_ownership.py +0 -97
  189. xdog_coding-2.4.1/tests/test_active_tool_retirement.py +0 -260
  190. xdog_coding-2.4.1/tests/test_active_tool_selection_terminal.py +0 -73
  191. xdog_coding-2.4.1/tests/test_active_tool_selection_ui.py +0 -171
  192. xdog_coding-2.4.1/tests/test_active_tools_after_run_hosts.py +0 -192
  193. xdog_coding-2.4.1/tests/test_active_tools_after_run_terminal.py +0 -75
  194. xdog_coding-2.4.1/tests/test_after_run_compaction.py +0 -272
  195. xdog_coding-2.4.1/tests/test_after_run_compaction_terminal.py +0 -119
  196. xdog_coding-2.4.1/tests/test_after_run_name.py +0 -185
  197. xdog_coding-2.4.1/tests/test_after_run_name_terminal.py +0 -121
  198. xdog_coding-2.4.1/tests/test_argument_completion_session.py +0 -92
  199. xdog_coding-2.4.1/tests/test_argument_completion_ui.py +0 -206
  200. xdog_coding-2.4.1/tests/test_callback_inspection.py +0 -160
  201. xdog_coding-2.4.1/tests/test_child_active_tools.py +0 -125
  202. xdog_coding-2.4.1/tests/test_child_image_submission.py +0 -495
  203. xdog_coding-2.4.1/tests/test_child_queue_ui.py +0 -118
  204. xdog_coding-2.4.1/tests/test_claw_active_tools_terminal.py +0 -111
  205. xdog_coding-2.4.1/tests/test_claw_elicitation_terminal.py +0 -126
  206. xdog_coding-2.4.1/tests/test_claw_sampling_terminal.py +0 -88
  207. xdog_coding-2.4.1/tests/test_command_artifact_export_ui.py +0 -113
  208. xdog_coding-2.4.1/tests/test_command_help_ui.py +0 -128
  209. xdog_coding-2.4.1/tests/test_command_lifecycle_ui.py +0 -109
  210. xdog_coding-2.4.1/tests/test_compaction_controls_ui.py +0 -483
  211. xdog_coding-2.4.1/tests/test_context_message_persistence.py +0 -114
  212. xdog_coding-2.4.1/tests/test_custom_delivery_modes.py +0 -371
  213. xdog_coding-2.4.1/tests/test_custom_delivery_terminal.py +0 -221
  214. xdog_coding-2.4.1/tests/test_draft_durability_terminal.py +0 -38
  215. xdog_coding-2.4.1/tests/test_editor_write_terminal.py +0 -58
  216. xdog_coding-2.4.1/tests/test_editor_write_ui.py +0 -209
  217. xdog_coding-2.4.1/tests/test_exact_command_ui.py +0 -100
  218. xdog_coding-2.4.1/tests/test_extension_catalog_ui.py +0 -122
  219. xdog_coding-2.4.1/tests/test_extension_command_catalog_ui.py +0 -120
  220. xdog_coding-2.4.1/tests/test_extension_command_results_ui.py +0 -101
  221. xdog_coding-2.4.1/tests/test_extension_compaction_terminal.py +0 -133
  222. xdog_coding-2.4.1/tests/test_extension_compaction_ui.py +0 -77
  223. xdog_coding-2.4.1/tests/test_extension_context_message_terminal.py +0 -72
  224. xdog_coding-2.4.1/tests/test_extension_context_message_ui.py +0 -79
  225. xdog_coding-2.4.1/tests/test_extension_custom_ui.py +0 -401
  226. xdog_coding-2.4.1/tests/test_extension_dialogs.py +0 -136
  227. xdog_coding-2.4.1/tests/test_extension_editor_ui.py +0 -100
  228. xdog_coding-2.4.1/tests/test_extension_entries.py +0 -85
  229. xdog_coding-2.4.1/tests/test_extension_failure_projection.py +0 -186
  230. xdog_coding-2.4.1/tests/test_extension_input_ui.py +0 -289
  231. xdog_coding-2.4.1/tests/test_extension_message_terminal.py +0 -67
  232. xdog_coding-2.4.1/tests/test_extension_message_ui.py +0 -84
  233. xdog_coding-2.4.1/tests/test_extension_navigation_ui.py +0 -206
  234. xdog_coding-2.4.1/tests/test_extension_nested_ui.py +0 -110
  235. xdog_coding-2.4.1/tests/test_extension_provider_auth.py +0 -100
  236. xdog_coding-2.4.1/tests/test_extension_provider_auth_terminal.py +0 -100
  237. xdog_coding-2.4.1/tests/test_extension_provider_capabilities.py +0 -84
  238. xdog_coding-2.4.1/tests/test_extension_provider_dynamic.py +0 -87
  239. xdog_coding-2.4.1/tests/test_extension_provider_startup.py +0 -111
  240. xdog_coding-2.4.1/tests/test_extension_provider_ui.py +0 -124
  241. xdog_coding-2.4.1/tests/test_extension_queued_input_terminal.py +0 -69
  242. xdog_coding-2.4.1/tests/test_extension_queued_input_ui.py +0 -197
  243. xdog_coding-2.4.1/tests/test_extension_results_ui.py +0 -133
  244. xdog_coding-2.4.1/tests/test_extension_session_context_ui.py +0 -154
  245. xdog_coding-2.4.1/tests/test_extension_session_name_ui.py +0 -182
  246. xdog_coding-2.4.1/tests/test_extension_shortcuts_ui.py +0 -90
  247. xdog_coding-2.4.1/tests/test_hook_lifecycle_ui.py +0 -114
  248. xdog_coding-2.4.1/tests/test_idle_message_images.py +0 -129
  249. xdog_coding-2.4.1/tests/test_idle_message_images_terminal.py +0 -70
  250. xdog_coding-2.4.1/tests/test_mcp_browser.py +0 -297
  251. xdog_coding-2.4.1/tests/test_mcp_catalog_watch_ui.py +0 -147
  252. xdog_coding-2.4.1/tests/test_mcp_combined_watch_ui.py +0 -165
  253. xdog_coding-2.4.1/tests/test_mcp_context_terminal.py +0 -105
  254. xdog_coding-2.4.1/tests/test_mcp_elicitation_recovery.py +0 -117
  255. xdog_coding-2.4.1/tests/test_mcp_elicitation_terminal.py +0 -125
  256. xdog_coding-2.4.1/tests/test_mcp_elicitation_ui.py +0 -150
  257. xdog_coding-2.4.1/tests/test_mcp_modern_browser_cancel.py +0 -55
  258. xdog_coding-2.4.1/tests/test_mcp_modern_browser_terminal.py +0 -226
  259. xdog_coding-2.4.1/tests/test_mcp_modern_browser_ui.py +0 -229
  260. xdog_coding-2.4.1/tests/test_mcp_resource_watch_ui.py +0 -117
  261. xdog_coding-2.4.1/tests/test_mcp_root_hosts.py +0 -95
  262. xdog_coding-2.4.1/tests/test_mcp_roots_review_ui.py +0 -162
  263. xdog_coding-2.4.1/tests/test_mcp_roots_terminal.py +0 -94
  264. xdog_coding-2.4.1/tests/test_mcp_sampling_catalog.py +0 -111
  265. xdog_coding-2.4.1/tests/test_mcp_sampling_context_hosts.py +0 -137
  266. xdog_coding-2.4.1/tests/test_mcp_sampling_terminal.py +0 -80
  267. xdog_coding-2.4.1/tests/test_mcp_sampling_ui.py +0 -139
  268. xdog_coding-2.4.1/tests/test_mcp_session.py +0 -92
  269. xdog_coding-2.4.1/tests/test_mcp_structured_ui.py +0 -115
  270. xdog_coding-2.4.1/tests/test_mcp_task_ci_ordering.py +0 -69
  271. xdog_coding-2.4.1/tests/test_mcp_task_hosts.py +0 -335
  272. xdog_coding-2.4.1/tests/test_mcp_task_terminal.py +0 -194
  273. xdog_coding-2.4.1/tests/test_menu_scope_ui.py +0 -156
  274. xdog_coding-2.4.1/tests/test_multi_forms_ui.py +0 -139
  275. xdog_coding-2.4.1/tests/test_oauth_ui.py +0 -381
  276. xdog_coding-2.4.1/tests/test_planning.py +0 -133
  277. xdog_coding-2.4.1/tests/test_provider_oauth_terminal.py +0 -77
  278. xdog_coding-2.4.1/tests/test_provider_oauth_ui.py +0 -219
  279. xdog_coding-2.4.1/tests/test_remote_parent_hash_changes.py +0 -275
  280. xdog_coding-2.4.1/tests/test_remote_parent_terminal.py +0 -176
  281. xdog_coding-2.4.1/tests/test_renderer_contracts_ui.py +0 -205
  282. xdog_coding-2.4.1/tests/test_repository_review.py +0 -161
  283. xdog_coding-2.4.1/tests/test_rpc_active_tools.py +0 -124
  284. xdog_coding-2.4.1/tests/test_rpc_canonical.py +0 -251
  285. xdog_coding-2.4.1/tests/test_rpc_capability_atomicity.py +0 -199
  286. xdog_coding-2.4.1/tests/test_rpc_child_canonical.py +0 -304
  287. xdog_coding-2.4.1/tests/test_rpc_child_contributions.py +0 -113
  288. xdog_coding-2.4.1/tests/test_rpc_child_custom.py +0 -270
  289. xdog_coding-2.4.1/tests/test_rpc_child_editor_write.py +0 -52
  290. xdog_coding-2.4.1/tests/test_rpc_child_events.py +0 -190
  291. xdog_coding-2.4.1/tests/test_rpc_child_extension_queued_inputs.py +0 -198
  292. xdog_coding-2.4.1/tests/test_rpc_child_overlay.py +0 -141
  293. xdog_coding-2.4.1/tests/test_rpc_child_terminal.py +0 -370
  294. xdog_coding-2.4.1/tests/test_rpc_child_terminal_lifecycle.py +0 -125
  295. xdog_coding-2.4.1/tests/test_rpc_children.py +0 -942
  296. xdog_coding-2.4.1/tests/test_rpc_children_cli.py +0 -503
  297. xdog_coding-2.4.1/tests/test_rpc_command_catalog.py +0 -126
  298. xdog_coding-2.4.1/tests/test_rpc_compaction.py +0 -344
  299. xdog_coding-2.4.1/tests/test_rpc_contributions.py +0 -132
  300. xdog_coding-2.4.1/tests/test_rpc_custom_backpressure.py +0 -140
  301. xdog_coding-2.4.1/tests/test_rpc_custom_contribution_integration.py +0 -91
  302. xdog_coding-2.4.1/tests/test_rpc_custom_delivery.py +0 -295
  303. xdog_coding-2.4.1/tests/test_rpc_custom_keyboard.py +0 -151
  304. xdog_coding-2.4.1/tests/test_rpc_custom_refresh.py +0 -71
  305. xdog_coding-2.4.1/tests/test_rpc_custom_views.py +0 -436
  306. xdog_coding-2.4.1/tests/test_rpc_deferred_delivery.py +0 -120
  307. xdog_coding-2.4.1/tests/test_rpc_editor.py +0 -269
  308. xdog_coding-2.4.1/tests/test_rpc_editor_write.py +0 -173
  309. xdog_coding-2.4.1/tests/test_rpc_events.py +0 -327
  310. xdog_coding-2.4.1/tests/test_rpc_extension_browser.py +0 -156
  311. xdog_coding-2.4.1/tests/test_rpc_extension_catalog.py +0 -156
  312. xdog_coding-2.4.1/tests/test_rpc_extension_compaction.py +0 -180
  313. xdog_coding-2.4.1/tests/test_rpc_extension_context_messages.py +0 -75
  314. xdog_coding-2.4.1/tests/test_rpc_extension_message.py +0 -291
  315. xdog_coding-2.4.1/tests/test_rpc_extension_name.py +0 -134
  316. xdog_coding-2.4.1/tests/test_rpc_extension_navigation.py +0 -398
  317. xdog_coding-2.4.1/tests/test_rpc_extension_queued_inputs.py +0 -175
  318. xdog_coding-2.4.1/tests/test_rpc_extensions.py +0 -448
  319. xdog_coding-2.4.1/tests/test_rpc_host_generation.py +0 -75
  320. xdog_coding-2.4.1/tests/test_rpc_image_uploads.py +0 -228
  321. xdog_coding-2.4.1/tests/test_rpc_images.py +0 -288
  322. xdog_coding-2.4.1/tests/test_rpc_menu_scope.py +0 -229
  323. xdog_coding-2.4.1/tests/test_rpc_mode.py +0 -93
  324. xdog_coding-2.4.1/tests/test_rpc_navigation.py +0 -706
  325. xdog_coding-2.4.1/tests/test_rpc_output.py +0 -144
  326. xdog_coding-2.4.1/tests/test_rpc_overlay.py +0 -143
  327. xdog_coding-2.4.1/tests/test_rpc_parent_draft_interlocks.py +0 -73
  328. xdog_coding-2.4.1/tests/test_rpc_parent_draft_terminal.py +0 -60
  329. xdog_coding-2.4.1/tests/test_rpc_parent_drafts.py +0 -458
  330. xdog_coding-2.4.1/tests/test_rpc_parent_terminal.py +0 -276
  331. xdog_coding-2.4.1/tests/test_rpc_physical_editing.py +0 -85
  332. xdog_coding-2.4.1/tests/test_rpc_physical_terminal.py +0 -85
  333. xdog_coding-2.4.1/tests/test_rpc_session_lifecycle.py +0 -263
  334. xdog_coding-2.4.1/tests/test_rpc_shutdown_delivery.py +0 -96
  335. xdog_coding-2.4.1/tests/test_rpc_structured_layout.py +0 -146
  336. xdog_coding-2.4.1/tests/test_rpc_terminal_approval_revision.py +0 -93
  337. xdog_coding-2.4.1/tests/test_rpc_terminal_keymap.py +0 -178
  338. xdog_coding-2.4.1/tests/test_rpc_transcript_cli.py +0 -143
  339. xdog_coding-2.4.1/tests/test_rpc_transcripts.py +0 -444
  340. xdog_coding-2.4.1/tests/test_rpc_transient_backpressure.py +0 -69
  341. xdog_coding-2.4.1/tests/test_saved_source_ui.py +0 -251
  342. xdog_coding-2.4.1/tests/test_skill_controls_ui.py +0 -199
  343. xdog_coding-2.4.1/tests/test_terminal_acceptance.py +0 -8274
  344. xdog_coding-2.4.1/tests/test_terminal_input_ui.py +0 -372
  345. xdog_coding-2.4.1/tests/test_terminal_release_physical.py +0 -153
  346. xdog_coding-2.4.1/tests/test_tool_inventory_ui.py +0 -263
  347. xdog_coding-2.4.1/tests/test_tool_lifecycle_ui.py +0 -215
  348. xdog_coding-2.4.1/tests/test_ui_clear.py +0 -100
  349. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/.gitignore +0 -0
  350. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/LICENSE +0 -0
  351. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/LICENSE-EXCEPTION.md +0 -0
  352. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/cli/__init__.py +0 -0
  353. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/cli/config_selector.py +0 -0
  354. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/cli/file_processor.py +0 -0
  355. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/cli/initial_message.py +0 -0
  356. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/cli/list_models.py +0 -0
  357. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/cli/session_picker.py +0 -0
  358. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/__init__.py +0 -0
  359. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/bash_executor.py +0 -0
  360. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/canonical_source.py +0 -0
  361. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/compaction/__init__.py +0 -0
  362. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/compaction/compaction.py +0 -0
  363. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/compaction/utils.py +0 -0
  364. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/defaults.py +0 -0
  365. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/event_bus.py +0 -0
  366. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/exec_utils.py +0 -0
  367. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/extensions/__init__.py +0 -0
  368. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/extensions/loader.py +0 -0
  369. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/extensions/runner.py +0 -0
  370. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/extensions/types.py +0 -0
  371. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/keybindings.py +0 -0
  372. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/messages.py +0 -0
  373. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/model_catalog.py +0 -0
  374. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/remote_session.py +0 -0
  375. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/resource_loader.py +0 -0
  376. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/timings.py +0 -0
  377. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/core/tools/__init__.py +0 -0
  378. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/__init__.py +0 -0
  379. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/__init__.py +0 -0
  380. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/__init__.py +0 -0
  381. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/assistant_message.py +0 -0
  382. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/editor_layout.py +0 -0
  383. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/footer.py +0 -0
  384. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/permission_prompt.py +0 -0
  385. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/tool_execution.py +0 -0
  386. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/components/user_message.py +0 -0
  387. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/provider_auth.py +0 -0
  388. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/run_status.py +0 -0
  389. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/theme.py +0 -0
  390. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/interactive/tool_renderers.py +0 -0
  391. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/modes/print_mode.py +0 -0
  392. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/py.typed +0 -0
  393. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/utils/__init__.py +0 -0
  394. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/utils/frontmatter.py +0 -0
  395. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/utils/git.py +0 -0
  396. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/utils/mime.py +0 -0
  397. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/utils/shell.py +0 -0
  398. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/src/xdog/coding/utils/sleep.py +0 -0
  399. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/fixtures/benchmark_tui.py +0 -0
  400. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_agent_session.py +0 -0
  401. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_cli_args.py +0 -0
  402. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_cli_config_selector.py +0 -0
  403. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_cli_file_processor.py +0 -0
  404. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_coding_config.py +0 -0
  405. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_compaction_recovery.py +0 -0
  406. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_context_message_compaction.py +0 -0
  407. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_event_bus.py +0 -0
  408. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_footer_context.py +0 -0
  409. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_interactive_keymap.py +0 -0
  410. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_messages.py +0 -0
  411. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_owned_native_model.py +0 -0
  412. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_prompt_templates.py +0 -0
  413. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_resource_loader.py +0 -0
  414. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_run_status.py +0 -0
  415. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_sdk_compaction_compat.py +0 -0
  416. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_sdk_runtime_compatibility.py +0 -0
  417. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_session_manager.py +0 -0
  418. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_session_navigation.py +0 -0
  419. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_session_picker.py +0 -0
  420. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_settings_manager.py +0 -0
  421. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_slash_commands.py +0 -0
  422. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_slash_skills.py +0 -0
  423. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_system_prompt.py +0 -0
  424. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_timings.py +0 -0
  425. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_tools_browser.py +0 -0
  426. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_transcript_interaction.py +0 -0
  427. {xdog_coding-2.4.1 → xdog_coding-2.4.2}/tests/test_transcript_output.py +0 -0
@@ -0,0 +1,2624 @@
1
+ Metadata-Version: 2.5
2
+ Name: xdog-coding
3
+ Version: 2.4.2
4
+ Summary: Interactive coding agent CLI
5
+ Project-URL: Homepage, https://xdog.942295.xyz
6
+ Project-URL: Repository, https://github.com/litterzhang/xdog
7
+ Project-URL: Documentation, https://xdog.942295.xyz
8
+ Project-URL: Issues, https://github.com/litterzhang/xdog/issues
9
+ Author: HugeMan
10
+ License-Expression: AGPL-3.0-or-later
11
+ License-File: LICENSE
12
+ License-File: LICENSE-EXCEPTION.md
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: agent-client-protocol<0.13,>=0.12.1; python_version < '3.15'
23
+ Requires-Dist: click>=8.1.0
24
+ Requires-Dist: pydantic>=2.0
25
+ Requires-Dist: pyyaml>=6.0
26
+ Requires-Dist: xdog-agent>=2.4.2
27
+ Requires-Dist: xdog-ai[openai]>=2.4.2
28
+ Requires-Dist: xdog-tui>=2.4.2
29
+ Description-Content-Type: text/markdown
30
+
31
+ # xdog-coding
32
+
33
+ > Platform scope: **Linux only**. Non-Linux adapters and native-platform support
34
+ > are outside the current product scope; historical audit evidence is not a support promise.
35
+
36
+ **Interactive coding-agent CLI.**
37
+
38
+ A terminal coding agent with session management, built on
39
+ [`xdog-agent`](https://pypi.org/project/xdog-agent/) and the
40
+ [`xdog-tui`](https://pypi.org/project/xdog-tui/) rendering layer.
41
+
42
+ ```bash
43
+ uv run xdog-coding
44
+ ```
45
+
46
+ Resume a session from the current directory with `uv run xdog-coding -r`.
47
+ The selector lists all matching sessions, newest first. Use Up/Down, Page Up/Down,
48
+ Home/End and Enter to choose; Escape cancels. `--working-dir PATH` changes the
49
+ directory being listed. `--pick-session` opens the same selector.
50
+
51
+ `--resume-id ID` restores a session directly, including in non-interactive modes.
52
+ The selector shows current-directory sessions first, followed by older sessions
53
+ marked `[Unknown dir]` whose directory was never recorded. Choosing and resuming
54
+ an unknown session associates it with the current directory; canceling leaves it
55
+ unchanged. Sessions known to belong to other directories are excluded. Existing
56
+ saved model, messages and usage are preserved.
57
+
58
+ ## Interactive terminal
59
+
60
+ The interface uses native scrollback, one status row, and a shared multiline
61
+ editor. Enter submits or queues; Ctrl+Enter inserts a newline. Ctrl+O opens
62
+ recent tool/reasoning details: Left/Right chooses an entry and Page Up/Page Down
63
+ scrolls. Escape closes autocomplete/details first, then cancels active work and
64
+ restores queued text ahead of the current draft. Ctrl+Z suspends on POSIX.
65
+ Ctrl+L repaints the visible UI without clearing scrollback, the draft, or focus.
66
+ The terminal cursor is visible in the focused editor and hidden while inspecting
67
+ details or approving a tool; returning to input restores it at the draft position.
68
+ Streaming updates are processed in bounded FIFO batches so input and rendering
69
+ continue to get a turn under sustained output.
70
+
71
+ Permission prompts take priority. Up/Down chooses an action, Enter confirms,
72
+ Escape denies that call, and Page Up/Page Down scrolls the command summary.
73
+ Confirmation requires visible action/context; tiny or clipped previews ask you
74
+ to resize. Space, modified Enter and reported key repeats never approve.
75
+ The editor draft stays intact when panels open or the terminal resizes.
76
+ Exit, EOF and terminal failures cancel owned agent/pre-turn work, discard queued
77
+ execution and close approvals; cleanup is not limited to keyboard callbacks.
78
+ Slash commands are serialized. Model/session/skill changes require an idle agent;
79
+ commands rejected while busy and messages submitted during compaction remain in
80
+ the draft. Escape cancels asynchronous command work. Standard console warnings
81
+ are rendered as sanitized UI messages rather than printing over terminal frames.
82
+ Transcript messages use shared TUI components: user text, Thinking, assistant
83
+ prose and tool previews. Thinking and prose remain separate message objects during
84
+ streaming; the transcript controls spacing and tools use a bounded branch preview.
85
+ User messages have a subtle background and one blank separator before replies.
86
+ The light theme uses a pale background; plain/NO_COLOR mode omits colors.
87
+ See [terminal verification](../../docs/tui-pi-parity.md); remote coding and
88
+ fullscreen application modes are excluded.
89
+
90
+ Details and permission prompts appear below the input. Coding shows the actual activity and
91
+ retains final tool durations. Queue/context metadata takes priority over long
92
+ model names; `/status` displays full model, session and working-directory data.
93
+ Context displays used tokens / prompt capacity, including cached input tokens,
94
+ even when the percentage would round to zero. Resume restores user text blocks
95
+ in both the transcript and input history, alongside saved model and usage.
96
+ Ctrl+Enter, Shift+Enter and Alt+Enter insert a newline when the terminal forwards
97
+ the modified key. If a desktop shortcut intercepts Ctrl+Enter, rebind that shortcut
98
+ or use Alt+Enter; the application cannot override desktop window management.
99
+
100
+ - `/details` or Ctrl+O opens a focused panel, including feedback when empty.
101
+ - Left/Right selects an entry; PgUp/PgDn reads pages; Home reads from the top.
102
+ - Details always open at the first line, including tool logs. Page Up/Page Down
103
+ scrolls; End jumps to the latest entry/output and starts following new output.
104
+ - Thinking shows a two-row plain-text preview without opening details. Tool
105
+ summaries keep multiline scripts on one header row; full commands are in details.
106
+ - Escape, Ctrl+C or Ctrl+O closes details and restores the draft/cursor.
107
+ - Permission panels show summary position and identify session approval as
108
+ approval of the same call. Short terminals omit decorations and hints first.
109
+
110
+ Configure styling before launch:
111
+
112
+ ```bash
113
+ XDOG_TUI_THEME=native uv run xdog-coding # default: terminal-native body colors
114
+ XDOG_TUI_THEME=light uv run xdog-coding
115
+ XDOG_TUI_THEME=dark uv run xdog-coding
116
+ NO_COLOR=1 uv run xdog-coding # unstyled content
117
+ XDOG_TUI_ASCII=1 uv run xdog-coding # ASCII tool-state markers
118
+ XDOG_TUI_COLOR=16 uv run xdog-coding # force basic ANSI colors
119
+ XDOG_TUI_COLOR=256 uv run xdog-coding
120
+ XDOG_TUI_COLOR=truecolor uv run xdog-coding
121
+ ```
122
+
123
+ `XDOG_TUI_THEME=plain` also disables styling. `TERM=dumb` selects plain styling
124
+ and ASCII tool markers. Terminal-control sequences are still required for this
125
+ interactive mode; print mode is available for noninteractive output.
126
+
127
+ Color depth defaults to `auto`: `COLORTERM=truecolor/24bit` enables truecolor,
128
+ otherwise `TERM=*256color*` enables 256 colors, with a basic 16-color fallback.
129
+ The light theme supplies contrast-checked semantic colors for white backgrounds;
130
+ user-customized terminal palettes still need a visual check.
131
+
132
+ Compact tools use two text rows: name/state/duration/command, then an output
133
+ preview. Streaming previews retain the latest text; complete results remain
134
+ accessible in details. Rich image content may add rows. Permission prompts gain
135
+ a box when space permits, and shed it on short/narrow terminals.
136
+
137
+ The immutable UI run state tracks waiting, reasoning, responding, running,
138
+ permission and cancellation. Permission resolution restores the current work
139
+ phase; cancellation cannot be revived by progress events; completion clears
140
+ the timer. Worker locks and cancellation signals remain separate from UI state.
141
+
142
+ ## Tool permissions
143
+
144
+ Potentially mutating tool calls are gated immediately before execution. By
145
+ default, read-only filesystem operations and `current_time` run automatically;
146
+ `bash`, filesystem writes/edits/deletes, and unknown extension tools ask first.
147
+
148
+ ```bash
149
+ xdog-coding --permission-mode ask # default: ask for dangerous calls
150
+ xdog-coding --permission-mode ask-all # ask before every tool
151
+ xdog-coding --permission-mode allow-all # trusted unattended automation
152
+ xdog-coding --permission-mode deny # allow read-only calls only
153
+ ```
154
+
155
+ Interactive approvals offer **Allow once**, **Allow for this session** (the exact
156
+ same call only), and **Deny**. Non-interactive runs fail closed when no approver
157
+ is available unless `allow-all` was explicitly selected.
158
+
159
+ The same setting can be stored in `~/.config/xdog/coding/settings.json`:
160
+
161
+ ```json
162
+ {"permission_mode": "ask"}
163
+ ```
164
+
165
+ Permission prompts are an execution gate, not an OS sandbox: an approved shell
166
+ command still has the permissions of the `xdog-coding` process.
167
+
168
+ ## Part of xdog
169
+
170
+ This package is one piece of [xdog](https://github.com/litterzhang/xdog), a
171
+ local-first toolkit for building, running and scheduling LLM workflows. The
172
+ centrepiece is [`xdog-flow`](https://pypi.org/project/xdog-flow/) — a typed
173
+ workflow format and compiler.
174
+
175
+ Documentation: **https://xdog.942295.xyz**
176
+
177
+ ## Licence
178
+
179
+ Copyright (c) 2026 HugeMan <942295.xyz>
180
+
181
+ GNU Affero General Public License v3.0 or later — see
182
+ [LICENSE](https://github.com/litterzhang/xdog/blob/main/LICENSE).
183
+
184
+ ### Interactive file references
185
+
186
+ Type `@name` to fuzzy-search names under the session working directory, or use
187
+ `@src/`, `./`, `../`, `~/`, or an absolute path to browse a directory. Up/Down
188
+ selects a suggestion; Tab or Enter inserts it **without sending your draft**.
189
+ Directory selection continues browsing. Quote paths containing spaces, for
190
+ example `@"src/my file.py"`. Escape dismisses completion; Tab reopens it.
191
+ References remain prompt text, not eagerly read attachments or tool approval.
192
+
193
+ Name discovery and matching are asynchronous, resumable batches—not a total
194
+ 20,000-file cutoff. A private SQLite index keeps candidate storage off the UI
195
+ thread; progress appears within the editor's row budget. Git supplies nested
196
+ `.gitignore`, repository-local and global exclude rules, even outside a Git
197
+ repository using private temporary metadata. Tracked names remain eligible when
198
+ ignored, but deleted names are removed on refresh. Untracked generated/hidden
199
+ paths and directory symlink traversal are omitted. Explicit directory paths
200
+ bypass ignore rules without bypassing tool permissions.
201
+
202
+ Results refresh after three seconds. Without Git (or if enumeration fails), the
203
+ UI explicitly reports a resumable basic-exclusion fallback; Git ignore semantics
204
+ are then unavailable. No repository hooks/fsmonitor commands are enabled and no
205
+ workspace/index metadata is modified. See `docs/agent-ui-gap-plan.md` at the
206
+ repository root for verification and remaining parity work.
207
+
208
+ ### Keybindings and external editor
209
+
210
+ The live UI loads `$XDG_CONFIG_HOME/xdog/coding/keybindings.json` (or
211
+ `$CODING_DIR/keybindings.json`) on startup. It is a JSON object mapping action
212
+ names to one key string, a list of strings, or `[]` to disable the action:
213
+
214
+ ```json
215
+ {
216
+ "send": "ctrl+s",
217
+ "newline": "alt+n",
218
+ "details": "ctrl+t",
219
+ "external_editor": "f4"
220
+ }
221
+ ```
222
+
223
+ Overrides replace each action's default bindings. Conflicting, unknown, duplicate,
224
+ or malformed configuration is rejected as a whole with a UI diagnostic; defaults
225
+ remain active. Bare printable characters cannot be shortcuts. Escape and Ctrl+L
226
+ are reserved for contextual cancel/deny and recovery repaint; approval and dialog
227
+ navigation keys are not remapped. Modified keys require terminal reporting support.
228
+ Use **F1** or **`/keys`** to see the effective map, including editing, history,
229
+ undo/redo, kill/yank, interrupt, exit, suspend, details and editor actions. Restart
230
+ for configuration changes. Prompt hints show current bindings, not stale defaults.
231
+
232
+ **Ctrl+G** (by default) or **`/editor`** opens the composer in `$VISUAL`, then
233
+ `$EDITOR`, falling back to `vi`. Commands may contain quoted arguments; they are
234
+ not interpreted by a shell, and the temporary draft filename is appended. GUI
235
+ editors must be configured to wait for the file (for example their `--wait` flag).
236
+ Project settings and agent output cannot choose the editor command.
237
+
238
+ The external editor owns a cooked terminal while it runs. Its UTF-8 draft uses a
239
+ private directory and mode-0600 file, limited to 1 MiB and removed after exit.
240
+ Success updates the composer with undo support; **nothing is submitted**. Nonzero
241
+ exit, Ctrl+C interruption, invalid output or a missing program preserves the old
242
+ draft and cursor. Symlink/FIFO replacements are rejected. The TUI restores modes
243
+ even if the editor itself leaves raw input enabled, then re-anchors without
244
+ replaying native history or clearing scrollback. Editing requires prompt focus,
245
+ not a permission/details/overlay dialog.
246
+
247
+ Agent work can continue while the external editor owns the terminal; UI events
248
+ wait for the handoff to finish. Interrupting the editor does not undo tool effects
249
+ or cancel the agent: return to the prompt and use Escape for agent cancellation.
250
+ Linux/tmux behavior is automated; desktop editor/IME checks remain
251
+ manual and unverified.
252
+
253
+ ### Steering, native follow-ups, and editable queues
254
+
255
+ While a turn is active, there are three explicit delivery choices:
256
+
257
+ - **Enter** keeps the existing local FIFO: a new full turn after the active SDK
258
+ continuation settles, including normal prompt rebuild/compaction checks.
259
+ - **Alt+S** (default) or **`/steer TEXT`** queues text at the next SDK checkpoint.
260
+ It does not interrupt an already running model/tool call or undo tool effects.
261
+ - **Alt+F** (default) or **`/follow-up TEXT`** queues text after the active tool/
262
+ steering continuation, within the same SDK run.
263
+
264
+ These shortcuts are configurable as `steer`, `follow_up`, and `queue` actions.
265
+ **Ctrl+Q** or **`/queue`** inspects stable IDs, delivery lane and state. Local
266
+ next-turn IDs look like `q1`; runtime IDs look like `i1`. Use:
267
+
268
+ ```text
269
+ /queue edit q1 replacement text
270
+ /queue remove i2
271
+ /queue move i3 up
272
+ /queue move q2 down
273
+ ```
274
+
275
+ Moves operate within that delivery lane. A local edit applies under the queue
276
+ lock; runtime changes require an acknowledgement from the owning event loop.
277
+ Checkpoint-selected/consumed entries cannot be edited or removed. Replacement
278
+ text from a rejected edit stays in the draft. Queue inspection never resets the
279
+ active turn's timer. Edited queued text beginning with `/` remains literal agent
280
+ input, not an automatic slash command.
281
+
282
+ Acceptance means **queued**, not consumed. Consumption is reported only when the
283
+ input enters agent history. Cancellation returns only unconsumed runtime inputs;
284
+ these and local backlog are restored ahead of the live draft without automatic
285
+ resubmission. Idle/closing owners reject explicit delivery and preserve the text.
286
+ Local and identified runtime queues each permit 50 pending messages; runtime text
287
+ is limited to 64 KiB. Overflow rejects the new submission visibly, never drops old
288
+ messages. Tool approvals and Escape denial are unchanged.
289
+
290
+ These controls concern the primary composer/current parent run. The child-input
291
+ queue viewer is read-only; child queue mutation/recovery stays in the main-Agent/
292
+ SDK path described below.
293
+
294
+
295
+ ### In-session browsing and conversation trees
296
+
297
+ **Alt+R / `/sessions`** opens a searchable, paginated browser while retaining the
298
+ composer draft. `/tree` opens the active session's branches and stable history
299
+ checkpoints. In either panel: `/` searches (atomic paste supported), Up/Down and
300
+ PgUp/PgDn navigate, Right enters a session/branch tree, Left goes back, Enter
301
+ activates, `r` refreshes, and `n` creates a new session. Escape first exits search,
302
+ then closes the panel. `sessions`/`tree` are configurable keymap actions; tree is
303
+ unbound by default to avoid stealing existing Alt+T custom shortcuts.
304
+
305
+ `/name` inspects the current session name; `/name NAME` sets a durable plain-text
306
+ name and `/name -` clears it. Names take precedence over automatic summaries in
307
+ session-browser titles/search; they never replace conversation content or model
308
+ instructions. Unicode is retained (256 UTF-8 bytes maximum); line/terminal controls
309
+ and bidi overrides are rejected. Naming requires an idle current owner, makes no
310
+ model/tool calls, and does not activate a session or rewrite its history.
311
+
312
+ Coding publishes a name only after its atomic session save succeeds and retains
313
+ the same access/extension persistence owner. Existing unnamed sessions remain valid;
314
+ model summaries, branches and subsequent metadata saves retain explicit names.
315
+
316
+ `/resume ID`, `/new`, `/fork [INDEX]`, `/branch [SESSION] ID`, and
317
+ `/goto [SESSION [BRANCH|-]] INDEX` expose the same operations. Message indexes are
318
+ one-based. Browsing is read-only and can coexist with an active turn; activation,
319
+ new sessions and branch/checkpoint changes require an idle agent and use the
320
+ owned command lifecycle. A rejected activation is not silently queued for later.
321
+
322
+ Switching retains saved context/model/reasoning/instructions, rebinds built-in
323
+ workspace tools and file completion, rebuilds project context, and clears old
324
+ session approvals/active skills/queues without relaxing the current permission
325
+ mode. Old session heads are persisted before switching. Branches record parent
326
+ lineage; navigation saves a return checkpoint before replacing the current head.
327
+ Tool-call/result batches cannot be split into invalid provider context. Session
328
+ writes are atomic private temporary-file replacements; traversal IDs/symlink
329
+ session files are refused. These are persistence guards, not OS isolation.
330
+
331
+ ### Real images and explicit clipboard paste
332
+
333
+ `/attach PATH` reads a PNG/JPEG/WebP file into the editable draft (quote spaces).
334
+ `/attachments` lists stable IDs, names, dimensions and sizes;
335
+ `/attachments preview ID`, `/attachments remove ID`, and `/attachments clear`
336
+ inspect or change the draft without sending. The bounded preview uses terminal
337
+ image support when available and metadata fallback otherwise; Escape returns to
338
+ the draft. An active approval keeps priority over previews and clipboard results.
339
+
340
+ **Ctrl+V** (configurable `paste_clipboard`) or `/paste` explicitly reads the local
341
+ clipboard off-thread. Linux Wayland uses `wl-paste`; X11 uses `xclip`.
342
+ Missing helpers, unsupported formats and timeouts
343
+ are visible; ordinary terminal/bracketed text paste remains available. There is
344
+ no background clipboard polling. Late reads after submission remain in the new
345
+ editable draft, never auto-send; explicit `/attachments clear` discards pending
346
+ read results too.
347
+
348
+ Enter can submit an image-only draft. Up to **4 images**, **10 MiB each**, and
349
+ **40 MiB retained** across draft/queues are accepted, subject to stricter model
350
+ limits and an advertised image-input capability. Unknown/text-only capabilities
351
+ reject visibly and preserve the draft. Validation checks MIME/header/dimensions
352
+ (maximum 100 megapixels), not a full decoder or a security boundary. CLI `--file`
353
+ image inputs also become typed image content in print mode rather than path
354
+ placeholders. Image bytes are persisted in session history: treat those files as
355
+ sensitive.
356
+
357
+ Local queue edits/reorders and explicit steering/follow-ups retain their image
358
+ parts. `/queue` shows attached-image counts; removing a queue item releases its
359
+ attachments. Rejected/unconsumed inputs and failed turns preserve recoverable
360
+ bytes for explicit inspection/retry. Images from a completed turn are not returned
361
+ just because a later queued turn failed. Recovery never silently resends; a failed
362
+ provider input may already be in context, so inspect before retrying. Normal input
363
+ caps can be exceeded only by lossless recovery; remove excess before resubmission.
364
+ Linux/private-tmux and controlled clipboard helpers are tested; desktop clipboard,
365
+ Other Linux terminal preview behavior remains
366
+ unverified; controlled helper tests do not
367
+ prove native-platform compatibility.
368
+
369
+ ### Transcript search, selection and optional fullscreen
370
+
371
+ **Alt+H / `/transcript [QUERY]`** opens the full retained transcript browser.
372
+ It reads source text, not Markdown's rendered layout or truncated tool previews:
373
+ user/assistant prose, reasoning, complete tool output/arguments and system notices
374
+ remain searchable. Tool arguments follow the existing presentation/redaction
375
+ policy; image bodies are not converted to visible base64. Search is literal and
376
+ Unicode-case-insensitive, with **every non-overlapping occurrence** navigable,
377
+ including repeated hits on a single long line. Selected matches pan horizontally
378
+ when needed.
379
+
380
+ - `/` edits the query; Enter finishes query editing without submitting a prompt.
381
+ **n / Shift+N** selects next/previous match, wrapping across the retained history.
382
+ - Up/Down, PgUp/PgDn and Home scroll source lines; Left/Right selects an adjacent
383
+ source entry. **Shift+Left/Right** pans horizontally.
384
+ - **v** begins/clears a whole-line range selection; navigation extends it, and
385
+ Shift+Up/Down can start a range. **a** selects the complete current source entry,
386
+ including lines outside the viewport. Escape clears a selection before closing.
387
+ - **r** refreshes an immutable source snapshot while retaining the source position
388
+ where possible; refresh clears selection. **End** refreshes and goes to the
389
+ latest retained source. Streaming continues normally; the browser does not
390
+ silently change selected source text underneath you.
391
+ - **f / `/fullscreen`** toggles an alternate-screen transcript viewport using the
392
+ full terminal height. `/transcript fullscreen`, `refresh`, and `close` are also
393
+ available. `transcript` and `fullscreen` are configurable keymap actions; the
394
+ fullscreen shortcut is unbound by default.
395
+
396
+ The default application still uses **native main-buffer scrollback**. Fullscreen
397
+ is opt-in and temporary, retains the original main-buffer painter, and re-anchors
398
+ its restored cursor after resize rather than replaying history. Draft/cursor,
399
+ queued images, active work and timers stay owned by the application. Escape or
400
+ Ctrl+C closes the viewer, not the agent. Approvals leave fullscreen, take focus,
401
+ and return to the inline browser after denial/resolution; fullscreen does not
402
+ resume automatically. Exit/EOF/failure restore terminal modes and screen ownership.
403
+ The viewer has no tool execution, session mutation, clipboard upload or network
404
+ operation. Copy/export/share remains separate work in the gap tracker.
405
+
406
+ Search covers retained client-visible context, including restored session history;
407
+ use `/sessions` to activate an archive. Hidden runtime instructions, other sessions
408
+ and binary image data are not silently exposed. Native terminal mouse/text
409
+ selection is unchanged; browser range selection is whole-line/entry based. Linux
410
+ private-tmux resize/screen-return/approval behavior is tested; desktop terminal,
411
+ Other Linux desktop/IME manual validation remains open.
412
+
413
+
414
+ ### Copy, private export and explicit local sharing
415
+
416
+ **Alt+C / `/copy [response|selection|entry|conversation|all]`** copies a captured
417
+ source snapshot, defaulting to the latest assistant response. A marked browser
418
+ selection is used by Alt+C when present. In the transcript browser, **y** copies
419
+ selected lines or the current entry; **e** chooses a local export destination and
420
+ **s** reviews a local share artifact (selection if marked, otherwise conversation).
421
+ These gestures never submit a prompt or execute a tool. Clipboard helpers are
422
+ `wl-copy` on Linux Wayland or `xclip` on X11. No helper means an
423
+ explicitly reported private temporary text file fallback, not silent OSC52 output.
424
+ Helper errors/timeouts are not retried because clipboard outcome may be uncertain.
425
+ The OS clipboard can expose text to other applications.
426
+
427
+ `/export PATH [text|md|json] [scope]` creates a private captured transcript file;
428
+ without PATH it opens a destination/review panel. Default scope is all retained
429
+ source, including tool/reasoning/notices. Existing files, final-path symlinks and
430
+ directories are never replaced. Parent directories must already exist. Creation
431
+ uses a private temporary file in that directory followed by exclusive atomic
432
+ publication; failures/cancellation before commit leave no partial destination.
433
+ Binary image bodies are not embedded: visible source has attachment indicators.
434
+
435
+ `/share PATH [scope]` always reviews before saving a portable **local HTML file**.
436
+ Default scope is user/assistant conversation, excluding tool output, reasoning and
437
+ system notices. Explicit selection/entry/all scopes can include private roles and
438
+ are listed in the review. Common credential patterns are redacted, but this is
439
+ heuristic—not a confidentiality guarantee. Review the preview and destination,
440
+ scroll with pages/arrows, Tab to edit the path, and press plain Enter to save only
441
+ when the complete review/confirmation is visible. Tiny geometry, resize races,
442
+ modified Enter, paste and unrendered/loading previews cannot confirm. Escape or
443
+ Ctrl+C cancels the output dialog, not agent work. An active Coding tool approval
444
+ has higher focus priority and does not grant sharing permission.
445
+
446
+ The HTML escapes source text and contains no scripts, remote resources, forms,
447
+ links or upload behavior; a restrictive CSP is embedded. Distributing the artifact
448
+ is your separate explicit action. No hosted service/control plane is required.
449
+ All preparation, helper execution and file I/O is off the terminal thread, with one
450
+ owned operation at a time. Source is immutable even if streaming continues. A
451
+ session/context change cancels an uncommitted review; already committed clipboard/
452
+ file changes cannot be rolled back or automatically replayed. `/copy cancel`,
453
+ `/export cancel` or `/share cancel` cancels a pending output operation.
454
+
455
+ Claw requires a ready updated full-source gateway. Prompt actions fetch source
456
+ before output; failed/stale/disconnected reads never copy/export a clipped or old
457
+ fallback. Selection/entry actions use only a settled verified browser snapshot.
458
+ Draft/cursor, queue/attachment ownership, native scrollback and terminal modes are
459
+ preserved. Linux tmux and controlled real clipboard helpers are verified; desktop
460
+ clipboard ownership outside these Linux fixtures remains unverified. Private
461
+ fallback files persist until you delete them. Kernel-blocked filesystem operations
462
+ cannot be forcibly interrupted; helper success may transfer clipboard ownership
463
+ to the platform's normal persistent clipboard process.
464
+
465
+ ### MCP stdio tools (first transport slice)
466
+
467
+ Global `settings.json` and project `.coding/settings.json` accept `mcp_servers`;
468
+ project entries override the same global server ID. Example:
469
+
470
+ ```json
471
+ {"mcp_servers": {"local": {"command": "python", "args": ["/trusted/server.py"], "timeout": 30}}}
472
+ ```
473
+
474
+ Configuration alone never executes a server. **`/mcp connect local`** explicitly
475
+ launches its configured argv in the session workspace—trust/review project commands
476
+ before doing this. `/mcp` opens the browser; `/mcp list` shows connection/protocol/tool status;
477
+ `/mcp refresh local` rediscovers schemas, and `/mcp disconnect local` releases the
478
+ owned process. Connection/schema changes require idle agent/command ownership and
479
+ run off the terminal loop. Workspace/session switching closes old connections,
480
+ removes old proxies and reloads layered project configuration. Exit requests owned
481
+ cleanup. Status does not print environment credentials.
482
+
483
+ Discovered namespaced tools enter the existing single SDK agent, not a second loop.
484
+ The normal permission hook still gates every external tool; untrusted MCP
485
+ `readOnlyHint` annotations cannot make it auto-approved. Unattended default/deny
486
+ modes do not execute these tools; `allow-all` remains the explicit exception.
487
+ Timeout/disconnect/late responses never automatically replay a call. See the Agent
488
+ README for current/legacy negotiation, schema validation, configured Roots and
489
+ limits. Explicit public-PKCE OAuth and inert context controls follow; removed
490
+ optional client input/task families are not pending supported features.
491
+
492
+ `mcp_servers` now also supports explicit current/legacy HTTP endpoints:
493
+
494
+ ```json
495
+ {"mcp_servers": {"remote": {"transport": "http", "url": "https://host.example/mcp",
496
+ "headers_env": {"Authorization": "MCP_AUTH_HEADER"}, "timeout": 30}}}
497
+ ```
498
+
499
+ The selected environment value is the full header value (for example, a Bearer
500
+ header), not printed in status. `/mcp connect remote` reuses the same idle-gated
501
+ management, SDK proxies and approval policy as stdio. HTTP JSON/SSE decoding,
502
+ metadata/header mirrors, legacy session lifecycle and explicit auth/redirect/errors
503
+ are documented in the Agent README. No calls are automatically replayed or tokens
504
+ refreshed. Explicit public-PKCE OAuth, credential storage and inert resource/prompt
505
+ controls are documented below. Configured static/environment credentials remain
506
+ separate and cannot be mixed with the OAuth Authorization header.
507
+
508
+
509
+ ### MCP browser and inert context previews
510
+
511
+ `/mcp` (or `/mcp browse`) opens a focused server browser. Nothing connects
512
+ implicitly. Select a server and use **c/d/r** to connect/disconnect/refresh;
513
+ **u/t/p** lists resources/templates/prompts. **/** filters, arrows navigate,
514
+ and **Enter** retrieves a preview, never model input. Template selection opens
515
+ an editable URI: resolve expressions explicitly before reading. Prompt selection
516
+ opens a JSON object of named-string arguments; Enter retrieves the prompt only.
517
+
518
+ In preview, **i** inserts text into the existing editable draft with an untrusted
519
+ MCP label; a separate normal submit is required to send it. Binary insertion is
520
+ refused, not silently converted/truncated. **e** starts the existing reviewed JSON
521
+ export, retaining base64/MIME data. Export remains local, requires confirmation,
522
+ and uses the selected workspace rather than guessing the TUI launch directory.
523
+ **Escape** returns to servers/closes; **Ctrl+C** closes the browser. These gestures
524
+ never grant external tool approval or invoke `tools/call` by themselves.
525
+
526
+ Coding reads run off the UI thread and cancel when the browser closes or is
527
+ replaced. Connection/schema mutations retain the existing owned command lifecycle.
528
+
529
+ The retained MCP surface includes explicit public-PKCE authorization, selected
530
+ credential storage, inert previews and manual catalog refresh below. Native
531
+ manual completion and optional Sampling/Elicitation/Tasks/Roots-management controls
532
+ are removed, not pending browser features. Binary/image resources are exportable,
533
+ not directly attached to model input. Broader third-party interoperability is not
534
+ inferred from these local controls.
535
+
536
+
537
+ Legacy HTTP MCP tools now support bounded cursor-based response recovery: an
538
+ interrupted SSE response can be retrieved with GET/`Last-Event-ID`, retaining the
539
+ original request identity and timeout. No second tool POST, automatic approval or
540
+ connection replay occurs. Concurrent calls keep separate cursors; cancellation,
541
+ auth/redirect/session errors and reset/exhausted cursors fail without replay.
542
+ Current stateless HTTP never sends recovery GETs. See the Agent README for limits.
543
+
544
+
545
+ ### Configured MCP Roots and retained transport continuations
546
+
547
+ Roots are **configured disclosure metadata only**. A server config may include
548
+ `"roots": [{"uri":"file:///absolute/workspace","name":"Workspace"}]`, at most
549
+ 16 validated local absolute file URIs. Nothing enumerates the filesystem, infers
550
+ Roots from cwd, grants tool access or creates an OS sandbox. Explicit connect
551
+ admits that configured disclosure to the selected peer; disconnect withdraws it.
552
+ There is no mutable Roots picker, enable/replace review or Roots-change UI.
553
+
554
+ Legacy `roots/list` answers stay within the configured connection ceiling. Modern
555
+ 2026-07-28 `input_required` responses remain supported for owned `tools/call`,
556
+ `prompts/get` and `resources/read`: only configured Roots and bounded opaque
557
+ `requestState` continuations are accepted. Original request arguments and identity
558
+ remain fenced; continuation rounds, embedded inputs, bytes and deadlines are
559
+ bounded. An unsupported sibling input rejects the round before any partial Roots
560
+ disclosure. Disconnect/cancel settles the original owner, not a successor.
561
+
562
+ **Sampling, Elicitation and MCP Tasks are removed** from SDK/native/gateway
563
+ registration, capability advertisement and review/control surfaces. Legacy
564
+ requests are refused; modern embedded unsupported families/task augmentation fail
565
+ closed, with no callback, model/tool work or partial completion. The former
566
+ Sampling/Elicitation/Tasks/Roots-management keys are not replacement controls.
567
+ Basic extension input/select/confirm and provider OAuth callbacks are separate
568
+ retained interfaces, not MCP Elicitation.
569
+
570
+ Ordinary modern Roots/request-state continuations do not authorize retrying an
571
+ uncertain operation. Active resource/catalog/combined subscriptions are removed.
572
+ Ordinary response-scoped SSE and request telemetry remain. Legacy cursor-based
573
+ **GET** recovery retains the
574
+ original identity/deadline and never repeats a tool **POST**; current stateless
575
+ HTTP does not acquire legacy GET resumption. No disconnect, failed response or
576
+ continuation silently reconnects, replays POSTs or expands configured disclosure.
577
+
578
+
579
+ ### Task planning and host read-only scope
580
+
581
+ The builtin **`xdog-planning`** skill uses ordinary conversation or task documents
582
+ for objectives, dependencies, acceptance criteria and evidence-backed progress.
583
+ It does not create a separate plan database, inspector, execution mode or model
584
+ loop. The former `/plan`, `PlanPanel` and `update_plan` UI/tool APIs are removed.
585
+ List it with `/skills` and activate it with `/xdog-planning [request]`.
586
+
587
+ Use the native host control separately:
588
+
589
+ ```text
590
+ /readonly on
591
+ /readonly status
592
+ /readonly off
593
+ ```
594
+
595
+ With host read-only scope on, only local `filesystem` read/ls/grep/find and
596
+ `current_time` tool calls are eligible; shell, workspace writes, MCP/extension
597
+ tools and child-control tools are blocked. Normal permission policy still applies
598
+ to eligible calls. Cached approvals, `allow-all`, skill text, model arguments and
599
+ delayed approvals cannot release or bypass this restriction. Keep planning notes
600
+ in the conversation while read-only; writing a task document still needs the
601
+ normal write permission outside that scope.
602
+
603
+ Only an explicit user `/readonly off` releases the host restriction. It does
604
+ **not** change permission mode, `allow_tools`, extension trust or child access,
605
+ and it grants no tool approvals or automatic execution. Access changes require
606
+ the original idle owner with child/storage work settled, persist before publication,
607
+ and do not submit a model turn. Claw additionally fences controls to its ready
608
+ original group/session/connection; uncertain requests are not replayed.
609
+
610
+ Access state survives session/branch restore. Historical saved planning state is
611
+ read only for compatibility: a retained restriction is not silently cleared by
612
+ navigation, and malformed state fails closed. These are host policy gates, not an
613
+ OS sandbox or a restriction on arbitrary trusted Python code.
614
+
615
+ ### Trusted Python extensions (runtime API v1)
616
+
617
+ Extensions now run in owned Python subprocesses, using the existing bounded stdio
618
+ transport/lifecycle owner rather than a second agent loop. They are **trusted local
619
+ code with your full user privileges**. Process ownership contains accidental output,
620
+ timeouts and cleanup; it is NOT an OS sandbox or filesystem/network confinement.
621
+ Imports, hooks and user-invoked commands can themselves have effects. Tool-use
622
+ permission is separate from trusting extension code.
623
+
624
+ Enable only selected IDs in user/global configuration, not project settings:
625
+
626
+ ```json
627
+ {"extensions": ["sample"], "extension_dir": "/home/user/.local/share/xdog/extensions",
628
+ "extension_settings": {"sample": {}}}
629
+ ```
630
+
631
+ Each selected directory contains `extension.yaml` (`name: sample`,
632
+ `entry_point: main`) and `main.py`. No recursive project scanning, installation,
633
+ package-manager call or workspace-authorized Python import occurs. Relative roots
634
+ resolve against the global configuration directory, not the project cwd. Global
635
+ names activate lazily at the first agent turn, `/extensions`, or extension command.
636
+
637
+ ```python
638
+ from xdog.agent.extensions import ExtensionAPI
639
+
640
+ def setup(api: ExtensionAPI):
641
+ async def echo(params, context):
642
+ return "echo: " + params.get("text", "")
643
+ async def hello(args, context):
644
+ api.notify("Hello from the explicitly trusted extension")
645
+ return "hello: " + args
646
+ api.tool("echo", "Echo text", {"type": "object", "properties": {
647
+ "text": {"type": "string"}}}, echo)
648
+ api.command("hello", "Say hello", hello)
649
+ api.status("ready", "Extension ready")
650
+ api.status("summary", "Bounded status text")
651
+ ```
652
+
653
+ Tools get collision-safe `ext_...` aliases; slash commands are namespaced as
654
+ `/ext-sample-hello ARGS`. The live completion provider reflects current commands.
655
+ `/extensions [list|reload NAME|unload NAME]` manages ONLY globally trusted IDs and
656
+ requires idle ownership. Commands do not silently submit an agent prompt. API v1
657
+ supports sync/async callbacks, session/turn/message/tool lifecycle events, pre-tool
658
+ veto/parameter transforms, post-tool text transforms, bounded notifications and
659
+ simple text status. Legacy Python pre/post/stop hook types remain compatible.
660
+
661
+ Rewritten tool arguments are schema-validated and checked by the host's ORIGINAL
662
+ permission and read-only gates AFTER transformation. A plugin cannot use the API
663
+ to grant tool approval/change host read-only scope, or mask a denied/failed call as success.
664
+ UI text is sanitized and row-bounded; direct plugin prints never paint the host
665
+ terminal. Timed-out/failed/canceled callbacks close their owned process, with no
666
+ replay. An unavailable selected extension makes pre-tool validation fail closed
667
+ until explicit unload/reload. Shutdown runs bounded stop hooks and reaps normal
668
+ owned process groups; cancellation cannot roll back already completed effects.
669
+
670
+ The supported extension surface is intentionally bounded, not full Pi API
671
+ compatibility. Durable entries/context hooks, typed tool/command results, registered
672
+ shortcuts and session-owned providers are documented below. Arbitrary custom
673
+ rendering/forms/layouts, raw terminal interception/observation and host editor/session
674
+ mutation APIs are removed. Code can deliberately escape normal process ownership;
675
+ do not load untrusted code.
676
+
677
+ Coding project/session settings cannot enable extensions; global/user configuration
678
+ is the trust source. Its regular approval mode still gates plugin tools, even after
679
+ activation, and read-only read-only still blocks them under `allow-all`. Workspace/
680
+ session switching closes the prior owner and clears old status/registrations.
681
+
682
+
683
+ ### Durable extension entries and context hooks
684
+
685
+ Extensions can now call `api.append_entry("note", {"text": "durable data"})` from
686
+ an active callback. Host-owned JSON entries are bounded, independently namespaced
687
+ per extension and committed before the callback receipt is returned. Subsequent
688
+ callback context contains that extension's `context["entries"]`; unload/reload
689
+ retains it. Session/new/branch activation follows the selected durable snapshot,
690
+ not process globals. Old owners cannot publish entry writes after navigation.
691
+ Close invalidates late writes, so shutdown callbacks should not append entries.
692
+
693
+ Register `api.context(callback)` to transform the ephemeral message list before
694
+ EACH model invocation. The callback receives serialized typed user/assistant/tool
695
+ content plus its entry snapshot and returns a message list. It may inject summaries
696
+ or filter complete history batches, but does not edit the canonical transcript,
697
+ system prompt, static cache prefix, host read-only scope or tool permissions. Coding also
698
+ composes an existing SDK transform before its extension pipeline.
699
+
700
+ ```python
701
+ def setup(api):
702
+ async def remember(args, context):
703
+ api.append_entry("note", {"text": args})
704
+ return "Saved entry"
705
+ async def model_context(messages, context):
706
+ notes = [row["data"]["text"] for row in context["entries"] if row["kind"] == "note"]
707
+ if notes:
708
+ messages.append({"role": "user", "content": [
709
+ {"type": "text", "text": "Context note: " + notes[-1]}]})
710
+ return messages
711
+ api.command("remember", "Persist a note", remember)
712
+ api.context(model_context)
713
+ ```
714
+
715
+ Unknown/system roles, unsupported parts, invalid images/signatures and incomplete/
716
+ invented tool-result batches fail explicitly, not by silently dropping content.
717
+ No-op transforms preserve original typed messages. Images and signed thinking/tool
718
+ parts survive chunked full-context transfers beyond the individual extension-worker
719
+ RPC frame limit.
720
+ Transfers are checksummed, order/identity fenced and spooled off-loop, with a 128 MiB
721
+ explicit context limit, 64 KiB blocks and an absolute whole-transfer deadline.
722
+
723
+ Entry capacity is 128 entries across a session, 16 KiB per entry and 512 KiB total.
724
+ Invalid/corrupt stored state fails instead of quietly resetting it. Persistence
725
+ failure keeps the previous snapshot. Cross-loop cancellation settles committed
726
+ metadata/file ownership before the host releases its lifecycle reservation; it
727
+ cannot roll back an already completed write. Context-hook failures disable the
728
+ extension and do not trigger another model call or automatic replay.
729
+
730
+ Durable entries and context hooks do not grant editor/session mutation, raw terminal
731
+ interception or custom-layout authority. Registered shortcuts, basic dialogs, rich
732
+ results and session-owned providers have their separate contracts below. Extension
733
+ code is still trusted code with the user's privileges, not an OS sandbox.
734
+
735
+ Coding saves entry snapshots with its session JSON and branch metadata. Resuming
736
+ invalid entries refuses the session instead of falling back to an unrestricted
737
+ replacement. Context contributions are not persisted as user chat messages.
738
+
739
+
740
+ ### Interactive extension dialogs
741
+
742
+ Active extension callbacks now support `await api.select(title, choices)`,
743
+ `await api.input(title, message="", default="")` and
744
+ `await api.confirm(title, message)`. Optional `timeout` is bounded to 0.1–600 s.
745
+ Select/input return `None` on cancel/no UI; confirm returns `False`. Cancel answers
746
+ this dialog only—it is not tool approval, permission revocation or automatic turn
747
+ submission. Trusted extension code decides what to do with the answer.
748
+
749
+ The worker suspends the callback and returns an owned pending-callback/dialog
750
+ receipt. The host displays a focused basic dialog, then resumes that SAME callback
751
+ with the validated answer; it does not rerun a command/tool to obtain the answer.
752
+ Multiple sequential dialogs work. Without an interactive host, canceled values are
753
+ returned immediately rather than hanging unattended execution.
754
+
755
+ Basic dialogs sanitize control codes, scroll long details, preserve the main editor
756
+ draft and input cursor, and require a rendered visible question/action before Enter can
757
+ answer. Select/confirm pastes do not submit; tiny/resize/release/repeat/unpainted
758
+ selection input cannot confirm. Escape/Ctrl+C cancel the dialog. Tool approval and
759
+ output review retain higher focus priority. An affirmative extension confirmation
760
+ never grants the underlying agent tool permission or switches host read-only scope.
761
+
762
+ Dialog IDs are host-generated and scoped to their session/request/run/connection.
763
+ Timeout, abort, navigation, disconnect and shutdown settle/cancel pending futures;
764
+ late/foreign answers cannot resume a successor's callback. Claw command waits are
765
+ connection-owned background jobs so the socket can still process UI replies and
766
+ other controls while the group remains reserved. Context-hook dialogs still share
767
+ the context transfer's absolute deadline; the UI does not renew model/transport
768
+ budgets. Callback effects remain trusted code, not OS-enforced isolation.
769
+
770
+ These are basic input/select/confirm dialogs, not plugin forms or a layout API.
771
+ Custom renderers, nested dialogs, extension overlays and terminal interception are
772
+ removed. Registered command shortcuts and submitted-input hooks remain separate;
773
+ none of these interfaces grants tool permission or full Pi API compatibility.
774
+
775
+
776
+ ### Supervised child agents
777
+
778
+ `/agents start TASK` starts bounded read-only child work. `/agents start --inherit
779
+ TASK` inherits the current host policy; it does not copy approval grants or bypass
780
+ read-only. Inspect with `/agents list` or `/agents inspect ID`; use `steer ID TEXT`,
781
+ `follow-up ID TEXT`, `cancel ID`, `wait ID` and `close ID` under `/agents`.
782
+ Parents also receive reserved `agent_spawn`/`agent_control` tools; children cannot
783
+ recursively delegate through their parent's supervision tools.
784
+
785
+ Children share the workspace, so coordinate conflicting writes. Context is copied
786
+ at admission through a complete tool/result checkpoint. Model/options/tool execution
787
+ mode are inherited. Defaults are three active children, 16 retained records,
788
+ 120-second execution deadline, 16 model calls and a 32,000 reported-token stop
789
+ threshold—not exact billing. Output limits are clamped; input accounting can
790
+ overshoot on the final request. Cleanup/persistence may outlast the execution deadline.
791
+
792
+ Each child has independent Coding approvals and extension workers/state. Parent
793
+ validation/context hooks and current read-only/permission gates remain authoritative;
794
+ rewritten effective arguments are checked before host approval. Approval panels
795
+ identify the child, queue concurrent questions, and preserve the editor draft.
796
+ Active children block navigation/policy/schema changes until canceled or settled.
797
+ Interrupt cancels children; exit joins ownership. Atomic session/branch-scoped child
798
+ sidecars retain final results and extension entries; interrupted work is never
799
+ restarted automatically. Closed results remain archived on disk. Corrupt catalogs
800
+ visibly disable delegation but do not disable the parent conversation. Shared parent pre-hooks remain serial; inherited validation
801
+ uses no-UI canceled dialog values rather than another run's interactive lease.
802
+
803
+ `/agents` opens a live roster; Enter or `/agents inspect ID` opens complete retained
804
+ child source with `/` search, navigation, selection, `f` optional fullscreen and
805
+ explicit copy/export/share review. Escape returns to the roster and parent draft.
806
+ `n` creates a task, Tab selects inherited access, `s`/`t` steer/follow-up, `c` cancels
807
+ and `x` archives, with visible specific confirmations. A pending wait does not block
808
+ cancel controls. `l` enables live snapshots without overwriting search/selection.
809
+ Source conversion runs on one coalescing worker; output review is child-scoped.
810
+ Complex extension forms are removed;
811
+ child extension dialogs use independent child/parent-session/UI leases, never another run's question owner.
812
+ Trusted Python callbacks remain unrestricted code; none of this is an OS sandbox.
813
+
814
+
815
+ Running child tools expose their latest reported progress through the same child
816
+ source/search view. It is explicitly live/pending, not a final result. Transient
817
+ progress has a separate 512 KiB escaped-JSON / 128-source display-retention budget;
818
+ clipping/omission is labeled and does not abort valid execution. Completed canonical
819
+ tool results replace progress; transient snapshots are not inserted into model history
820
+ or persisted as fabricated results. Source IDs preserve concurrent/reused-call ownership.
821
+
822
+
823
+ Child extension select/input/confirm dialogs now display the child identity and
824
+ resume the original suspended callback with actual user answers. An extension yes
825
+ is NOT tool approval or a host read-only transition. Input/select cancel returns None;
826
+ confirm cancel returns False. Detaching/exiting the origin UI settles pending
827
+ questions and subsequent child questions use canceled values; callbacks/work are
828
+ not replayed or automatically adopted after reconnect. Parent inherited validation
829
+ still uses silent no-UI answers to avoid borrowing its separate dialog reservation.
830
+ Complex extension forms are removed; basic child dialogs retain these ownership and cancellation checks.
831
+
832
+
833
+ ### Child specialization and limits
834
+
835
+ `/agents start --label Reviewer --instructions "Inspect only" --tools filesystem,current_time
836
+ --fresh --timeout 60 --calls 4 --tokens 8000 -- TASK` specializes a child without
837
+ changing parent permissions. Options precede the task; `--` preserves a task that
838
+ starts with flags. Plain tasks preserve quotes/newlines. `--tools none` gives the
839
+ child no executable tools; otherwise selected names must exist in its inherited tool
840
+ set and cannot include recursive delegation tools. Unknown/malformed flags
841
+ fail visibly. Instructions append to, rather than replace, parent restrictions.
842
+
843
+ In `/agents` press `n`, then Ctrl+G for settings JSON. Supported keys are `label`,
844
+ `instructions`, `tools` (array or null for inherited tools), `inherit_context`,
845
+ `timeout`, `max_model_calls` and `max_tokens`. Enter applies the settings draft only;
846
+ start review requires every page to be painted before confirmation. Resize invalidates
847
+ that review. This confirmation does NOT approve tool use. Effective settings persist
848
+ with child results and appear in complete child source. Request/token caps may be
849
+ lowered, not raised above 16 / 32,000; token usage is not exact billable accounting.
850
+ `--fresh` omits canonical history/child entry inheritance, not mandatory parent
851
+ validation/context or the shared workspace. Model/reasoning inherit by default; explicit overrides now use the actual adapter.
852
+ Named presets now use explicit user configuration. Claw specialized
853
+ starts require its advertised `child_config` capability, avoiding silent old-gateway
854
+ settings loss.
855
+
856
+
857
+ ### Child model and reasoning overrides
858
+
859
+ `/agents start --model provider/model --thinking low --fresh TASK` selects child
860
+ routing/reasoning independently. Settings JSON accepts `model` (null inherits) and
861
+ `thinking` (null inherits, `off` disables, or advertised minimal/low/medium/high/xhigh).
862
+ Choices resolve on the SAME request adapter's cached active catalog; no automatic
863
+ provider activation/login/catalog sync/fallback occurs. Plain custom adapters without
864
+ metadata reject overrides. Claw requires `child_config: 2` for these fields.
865
+
866
+ Requested and effective routing/reasoning/limits persist separately in child source.
867
+ Selected capabilities/window/output limits apply, while parent/child read-only,
868
+ approval/external-tool gates remain unchanged. Same-model aliases preserve explicit
869
+ host native-tool overrides. Switching to a nonreasoning model disables inherited
870
+ reasoning; unsupported positive choices fail visibly. Model switches omit inherited/
871
+ transformed provider continuity and old reasoning from the CHILD copy, leaving parent
872
+ provenance/history intact. Transformed images are validated; oversized switched-model
873
+ contexts fail a conservative byte-based preflight with fresh/lower-output/larger-model
874
+ guidance, not automatic summarization or exact token accounting. Parent model/options/
875
+ settings/grants never change. Named presets now use explicit user configuration.
876
+
877
+
878
+ ### Named child presets
879
+
880
+ Define `child_presets` in Coding's user/global settings JSON or Claw's operator YAML
881
+ using this descriptor shape:
882
+
883
+ ```json
884
+ {
885
+ "child_presets": {
886
+ "reviewer": {
887
+ "description": "Inspect and report without workspace mutations",
888
+ "config": {
889
+ "instructions": "Review requested code; return findings with file locations.",
890
+ "tools": ["filesystem", "current_time"],
891
+ "inherit_context": false,
892
+ "max_model_calls": 4,
893
+ "max_tokens": 8000
894
+ }
895
+ }
896
+ }
897
+ }
898
+ ```
899
+
900
+ Browse `/agents presets`, or use `/agents start --preset reviewer --tokens 6000 --
901
+ TASK`. Explicit flags override template fields. Ctrl+P selects a template in a new
902
+ child form, Ctrl+G adjusts the draft, and full expanded settings/task review still
903
+ precedes execution. Selection itself makes no model request. Templates cannot encode
904
+ access/permission changes, code/imports, recursion or provider activation. Starts
905
+ remain read-only unless inherited access is explicitly selected separately; all host
906
+ gates remain active.
907
+
908
+ Frozen catalogs are bounded to 32 entries / 256 KiB raw and expanded data. Expanded
909
+ settings/provenance persist; catalog edits never replay historical work. Coding
910
+ project/session data cannot activate presets, and invalid global preset data retains
911
+ parent permission settings. Claw invalid operator templates fail without fallback;
912
+ preset controls require `child_config: 3`. Old schemas receive supported inherited
913
+ fields only; chosen nondefault routing/template settings are never silently dropped.
914
+
915
+
916
+ ### Interactive MCP authorization
917
+
918
+ `/mcp authorize SERVER` opens endpoint/resource/client/scope/TLS-trust consent; in
919
+ `/mcp` use `a` on the selected server. Page through EVERY field before Enter confirms.
920
+ Resize/tiny/unpainted/repeat/paste input cannot authorize. The resulting reviewed URI
921
+ is for your browser, not code/token paste into chat. `y` explicitly copies after full
922
+ URI review; no browser or model opens automatically. `c` cancels a pending callback,
923
+ `s` reads state, and Escape leaves the view and cancels pending ownership.
924
+
925
+ Authorization alone does not connect/register tools or approve execution. Return to
926
+ servers and `c` to connect explicitly. Server-list `s` inspects authorization,
927
+ `l` reviews saved restore and `x` reviews saved-credential erase. Inside authorization
928
+ status (not the server list), `f` reviews memory/saved forget and disconnect, never
929
+ remote revocation. Existing tool approvals,
930
+ Claw allow_tools/read-only and child/model rules remain active. Parent drafts/caret and
931
+ terminal modes survive. Tokens remain private in memory until a separate explicit
932
+ save to the selected Linux credential backend. Refresh/restore are explicit, with
933
+ no automatic retry or replay.
934
+
935
+ Consent is scoped to view/session/context and, in Claw, its original socket/group.
936
+ Another connection cannot use a known receipt. Leaving, canceling, disconnecting or
937
+ changing the scope rejects late credential commitment and settles pending listeners;
938
+ reconnect does not adopt a waiting flow. Already completed resource credentials may
939
+ survive closing the success view. Claw requires advertised `mcp_auth` controls; schema
940
+ changes/forget still require idle ownership. Pending HTTP jobs do not block socket
941
+ reads. Only pre-registered public-PKCE profiles are supported; client-metadata/DCR,
942
+ confidential methods and private-key JWT are removed. Explicit refresh and both
943
+ Linux storage choices below remain supported without method/store fallback.
944
+
945
+
946
+ ### Authorization metadata discovery
947
+
948
+ Resource denial challenges now retain their `resource_metadata` pointer and
949
+ operation-specific scopes for an explicit subsequent authorization, without replaying
950
+ failed MCP POSTs/tools. Quoted multi-scheme headers are parsed with bounds; malformed
951
+ or ambiguous challenges are not silently discarded. Without a pointer, path-specific
952
+ then root protected-resource metadata are tried. Issuers use ordered OAuth and OIDC
953
+ well-known candidates; only absent GET routes (404/405), never bad identity/200 data,
954
+ redirects or token/code errors, permit fallback.
955
+
956
+ Pointer metadata uses no existing MCP credentials/cookies. Its origin must be the
957
+ configured resource/issuer or an explicitly approved HTTPS origin in the optional
958
+ OAuth `metadata_origins` array (at most eight origin-only URLs). This approval does
959
+ not change the pinned issuer or authorization/token endpoint trust. Resource/issuer
960
+ identities still match exactly. Challenge scopes are operation-specific and take
961
+ priority without assuming they are listed in `scopes_supported`; the configured
962
+ scopes remain an operator ceiling. Scope-less listings are displayed as no request,
963
+ and over-ceiling requirements fail rather than silently expanding access. Actual
964
+ review data carries discovery URLs and scope-source provenance. Consent/permissions/
965
+ leases/explicit connect remain separate. Client-metadata and dynamic registration
966
+ are removed; explicit public refresh and both retained Linux stores do not imply
967
+ universal external-provider interoperability.
968
+
969
+
970
+ ### Pre-registered public-client boundary
971
+
972
+ MCP OAuth accepts only an existing **pre-registered public client ID**, S256 PKCE
973
+ and token authentication **`none`**. `registration: "pre-registered"` and
974
+ `token_auth_method: "none"` are the defaults and the only supported values.
975
+ Metadata-client-ID/hosted-client-document registration, dynamic registration,
976
+ confidential client-secret methods and private-key JWT/signing are removed.
977
+ Unsupported profiles fail closed before authentication/network work; no secret
978
+ source is read, signer started, registration POST sent or method/store fallback
979
+ attempted. There is no remote client-registration management API.
980
+
981
+ Pinned **resource/issuer metadata discovery** remains part of explicit public-PKCE
982
+ authorization; it is not client metadata registration. Resource, issuer, scopes,
983
+ TLS trust, loopback callback and actual endpoint review still apply. Authorization
984
+ never connects tools or grants their permission. Explicit reviewed refresh and
985
+ credential save/restore below remain independent operations, not automatic login
986
+ or recovery of an unsupported profile. Old records bound to removed authentication/
987
+ registration methods are not silently migrated or downgraded to public grants.
988
+
989
+
990
+ ### Explicit in-memory OAuth refresh
991
+
992
+ Refresh is an operator action, never a background token retry. If the issuer
993
+ supplied a refresh token, open authorization status and press **r**, review the
994
+ resource, actual grant scopes, pinned endpoints, client ID and public method
995
+ `none`, then confirm with a fresh physical Enter. This sends one resource-bound
996
+ refresh POST, not a new browser login or client registration. Claw requires
997
+ `mcp_refresh:1`; unsupported gateways cannot submit it.
998
+
999
+ SDK hosts use `manage_auth("remote", "refresh_prepare")` followed by
1000
+ `manage_auth("remote", "refresh", review_id)` under the same live consent lease.
1001
+ Receipts are single-use and expire after five minutes. Refresh uses the previous
1002
+ grant's scopes, not the broader configured ceiling. Valid replies may narrow,
1003
+ never widen, scopes. A new refresh token replaces the prior one only after reply
1004
+ validation; omission retains the old token only after a valid response.
1005
+
1006
+ The refresh capability is consumed before exchange. Cancellation, lost/invalid
1007
+ responses or revoked ownership discard it rather than replay an uncertain token.
1008
+ **c** cancels a pending refresh; leaving/disconnecting settles owned work and
1009
+ fences late commits. A still-valid old access token may remain usable after
1010
+ refresh failure; authorize again if needed. An existing saved snapshot is removed
1011
+ before rotating refresh, so restart cannot replay stale credentials. A completed
1012
+ replacement grant is saved only by another explicit reviewed save.
1013
+
1014
+ Refresh never replays MCP requests, connects tools, changes approvals or falls
1015
+ back to another client/authentication/storage method. The two retained Linux
1016
+ credential backends are documented separately; neither implies startup restore,
1017
+ automatic refresh, remote revocation or universal issuer interoperability.
1018
+
1019
+
1020
+ ### MCP JSON Schema and typed structured output
1021
+
1022
+ Current-protocol MCP results now retain **any finite JSON value** in structuredContent:
1023
+ objects, arrays, strings, numbers, booleans and explicit null. Missing content is
1024
+ tracked separately from null by `structured_content_present`; advertised output
1025
+ schemas must be satisfied. Legacy negotiated profiles still require object results.
1026
+ A successful text summary no longer hides canonical structured data: when no exact
1027
+ canonical JSON text block is already present, a labelled structured-output block is
1028
+ added to the tool content used by the model, full-source viewer and persistence.
1029
+ Compact rows may still collapse it; **Ctrl+O** or the transcript viewer inspects it.
1030
+
1031
+ JSON Schema defaults to 2020-12; recognized declared draft-04/06/07/2019-09/2020-12
1032
+ semantics are used rather than silently substituting another dialect. Local pointers,
1033
+ anchors/dynamic references and bundled resource IDs resolve only inside the advertised
1034
+ document. External documents are never fetched, including through an ID/base change.
1035
+ Unknown dialects, unresolved references and unsupported required vocabularies fail
1036
+ closed. Unreferenced examples/defaults remain data; explicitly referenced targets
1037
+ are checked as schemas. Normal nullable unions, boolean property schemas and
1038
+ conditionals are supported. MCP arguments remain objects; model parameters get an
1039
+ object-root intersection while validation keeps all raw advertised constraints.
1040
+
1041
+ MCP uses an optional sync/async AgentTool argument validator before permission hooks
1042
+ and validates effective arguments again immediately before the remote call. Coding
1043
+ and Claw extension pre-hooks use the same check when they rewrite arguments. Existing
1044
+ permission/read-only/allow_tools rules still decide execution; a schema/readOnly hint
1045
+ never approves a call. Coding's parameter prompt formatter now handles boolean/union
1046
+ property declarations rather than crashing on a valid schema.
1047
+
1048
+ The validation helper is local, owned and cancellable, started only for explicitly
1049
+ connected tool schemas. It runs isolated Python imports (`-I`) with only the trusted installed/vendored
1050
+ library root explicitly added, without a second
1051
+ agent/model loop or schema URL retrieval. A **three-second** deadline includes queue
1052
+ wait/validation; timeout/cancel kills and reaps that exact helper, including a child
1053
+ still being created. A later explicit validation may start a fresh local helper;
1054
+ remote MCP calls are never retried by it. Serialized schema caching is capped at
1055
+ 32 entries/4 MiB. Schema/value bytes, depth and node counts are bounded; these are
1056
+ application limits, **not** OS-enforced filesystem/network/memory sandboxing.
1057
+
1058
+ Bounded JSON tool details now survive save/reload/branches in both clients, preserving
1059
+ typed structured output and null-presence flags. Live/non-JSON handles stay transient.
1060
+ Transcripts may contain sensitive structured values: keep them private. Actual current/
1061
+ legacy peers, both app permission paths and Linux/private-tmux inspectors are verified;
1062
+ provider-specific full-schema acceptance and mixed-dialect/native-platform
1063
+ interoperability are not inferred. Format-assertion/custom required vocabularies,
1064
+ ambiguous HTTP header mappings through schema composition, richer content/client
1065
+ capabilities and external credential/provider interoperability gaps remain
1066
+ open. Earlier object-only/current structured-result limits are superseded by this pass.
1067
+
1068
+ Schema packaging includes a direct `referencing` dependency and the portable SDK
1069
+ bundle dependency list. The helper resolves its own trusted library root, so vendored
1070
+ bundles work without accepting project/PYTHONPATH shadow modules. An actual vendored
1071
+ helper test covers this; generated-output/vendored-package licence boundaries are
1072
+ unchanged. Lock updates only declare the already-resolved dependency, not unrelated
1073
+ version upgrades.
1074
+
1075
+ ### Rich extension tool results
1076
+
1077
+ Trusted extension tools are no longer text-only. Existing string callbacks are
1078
+ unchanged. A callback may return a typed `AgentToolResult`, a content/structuredContent/
1079
+ details object, or use the validated builder:
1080
+
1081
+ ```python
1082
+ return api.result([
1083
+ {"type": "text", "text": "Result summary"},
1084
+ {"type": "image", "data": png_base64, "mimeType": "image/png"},
1085
+ ], structured=[False, 0, None], details={"count": 0, "enabled": False})
1086
+ ```
1087
+
1088
+ Text and PNG/JPEG/WebP images remain typed through the one existing agent loop,
1089
+ model context, tool UI and transcript persistence. Structured JSON (including
1090
+ explicit null) remains canonical inspectable content, not hidden behind a summary.
1091
+ Extension metadata is separate: `extension_details_present` distinguishes omission
1092
+ from explicit null and `extension_details` retains the exact bounded JSON value.
1093
+ It is not converted to a model message or interpreted as host permissions. Typed
1094
+ AgentToolResult content/details is accepted too; structured data uses the builder
1095
+ or explicit structuredContent envelope.
1096
+
1097
+ Rich tool data is snapshotted and independently checked at worker and host boundaries.
1098
+ Unknown content kinds/extra fields, invalid image base64/MIME, nonfinite/non-JSON
1099
+ values, coercions and oversized frames fail rather than silently discard data.
1100
+ Limits: 64 content blocks, four images, 2 MiB decoded per image, 1 MiB per rich text
1101
+ block, 256 KiB each for structured data/details, and 3 MiB for the encoded rich
1102
+ result envelope. These are explicit API/frame limits, not OS-enforced sandboxing.
1103
+ No file/URI is implicitly opened and no image is automatically saved or attached
1104
+ as a new user prompt. Raise an exception for tool errors; rich isError/audio/resource
1105
+ payloads are not silently guessed in this API version. Commands remain bounded text.
1106
+
1107
+ Coding approvals, Claw extension_allow_tools, read-only and child inherited permission
1108
+ restrictions still gate execution. Text-only post-hooks do not replace or drop a
1109
+ result containing images. Legacy text callbacks/post-hooks retain their behavior.
1110
+ Both UIs display tool images without printing base64. Claw now forwards final tool
1111
+ image parts (previously missing from its display events), with a bounded live image
1112
+ budget. Larger generic tool images are visibly marked as omitted from the live
1113
+ preview; original data stays in canonical model/transcript history, not in an
1114
+ oversized socket line. The new rich-extension envelope fits that transport budget.
1115
+
1116
+ Independent real workers, denied/allowed live app paths, typed persistence, inherited
1117
+ child output, malformed/unsupported results, large-preview notices and both private-
1118
+ tmux image/JSON inspectors are verified. These typed tool results do not grant
1119
+ extension editor/session mutations, custom rendering or terminal interception.
1120
+ Audio/resource/error-image interoperability, remaining MCP/credential and native-
1121
+ platform gaps remain separate from the retained tool-result contract.
1122
+
1123
+ ### Rich extension command artifacts
1124
+
1125
+ Extension command callbacks now accept the same typed text/image/structured JSON/
1126
+ details result builder as tool callbacks. Legacy string commands remain strings.
1127
+ The SDK `runtime.command()` returns either str or a frozen `ExtensionCommandResult`
1128
+ with extension/command identity, a validated result snapshot and safe summary.
1129
+ For example, a command can return:
1130
+
1131
+ ```python
1132
+ return api.result([
1133
+ {"type":"text","text":"Command report"},
1134
+ {"type":"image","data":png_base64,"mimeType":"image/png"},
1135
+ ], structured=[False, 0, None], details={"enabled":False})
1136
+ ```
1137
+
1138
+ Both interactive clients append a **read-only command artifact**, not a tool result
1139
+ or agent message. Images render through the existing image component; base64 is not
1140
+ printed as prose. **Ctrl+O**/the transcript viewer inspects the complete text, typed
1141
+ JSON and details. Transcript copy/export can inspect its textual system-source
1142
+ record. Original image bytes and typed metadata remain owned in the local artifact;
1143
+ this does not pretend a text-only transcript export includes binary images.
1144
+
1145
+ Returning `/quit`, a URI or other command-looking text is data, never executed.
1146
+ Rich artifacts cannot trigger a model prompt, mutate the main draft, approve tools
1147
+ or change host read-only scope or permission modes. The prior draft/focus and normal approval
1148
+ priority remain; callbacks still require trusted activation/idle ownership. Results
1149
+ are fenced by command/session/connection identity; canceled/stale/foreign output is
1150
+ not appended to a new owner and callbacks are not replayed. Artifacts are local UI
1151
+ results, not newly persisted canonical agent-history entries or automatically saved
1152
+ files. Legacy command/builtin skill prompt behavior is unchanged.
1153
+
1154
+ Claw independently negotiates `extension_command_results: 1` in hello/pong. Its
1155
+ controlled response carries a validated artifact separately from the safe output
1156
+ summary. Older viewers get a visible update-required summary without image bytes,
1157
+ not a dict stringification containing base64; no callback is rerun to degrade it.
1158
+ New clients reject unnegotiated/malformed artifacts rather than guessing semantics.
1159
+ The rich envelope's existing byte/count/image/JSON limits apply, keeping control
1160
+ responses below the receiving transport budget.
1161
+
1162
+ Independent real command workers, both production UI paths, permission/draft/history
1163
+ non-mutation, system-source inspection, stale-owner rejection, older-viewer behavior,
1164
+ cancellation and malformed returns are tested, plus both private-tmux image/JSON
1165
+ inspectors and parent terminal restoration. Returning an artifact does not grant
1166
+ editor/session/navigation mutations, custom rendering/layouts or raw terminal access;
1167
+ those extension interfaces are removed. Read-only command inspection, provider
1168
+ registration and explicit artifact export/reload have their own contracts below.
1169
+
1170
+ ### Lossless command artifact export and read-only reload
1171
+
1172
+ `/export PATH artifact` captures the latest **owned** rich command artifact, including
1173
+ original image bytes, text, structured JSON and typed details. It is private JSON
1174
+ only (`json` may be explicit); implicit binary copy/share or lossy text/Markdown
1175
+ artifact export is refused. Supplying a path does NOT bypass review. The existing
1176
+ output panel shows image MIME/size/checksum and a no-redaction/sensitive-binary warning,
1177
+ without rendering base64. Enter writes only the reviewed immutable snapshot.
1178
+
1179
+ Files use the existing private 0600, same-directory staging/fsync and no-overwrite
1180
+ commit path. Cancel, hidden/tiny/resize review, owner/context changes and stale jobs
1181
+ cannot authorize an unreviewed write. A commit already made is not remotely undone;
1182
+ cancellation is not rollback. No upload, provider request, tool call or automatic
1183
+ artifact save is introduced. Ordinary textual transcript exports retain their prior
1184
+ semantics and are not falsely labelled binary exports.
1185
+
1186
+ `/artifact PATH` explicitly reads a bounded regular artifact file off the UI thread
1187
+ and appends a read-only image/JSON command display. It does not activate extensions,
1188
+ execute stored command names/text/URIs, change permissions or host read-only scope, or send input to
1189
+ the model. The 4 MiB file envelope is versioned as xdog.extension-command/v1; its
1190
+ SHA-256 covers canonical validated identity/content/metadata. Checksums detect
1191
+ corruption, NOT authenticity: treat files as untrusted data. Unsupported versions,
1192
+ tampered/malformed data, image/MIME/type failures and FIFO/nonregular inputs are
1193
+ refused. Original image bytes and false/zero/null/omission remain exact on reload.
1194
+
1195
+ Artifacts are selected by session/connection/history epoch. Old-owner results cannot
1196
+ be exported or appended to a new owner; loading snapshots publishes only under the
1197
+ captured context. A read can be canceled by closing/changing owner, suppressing late
1198
+ publication. An OS-blocked filesystem thread cannot be forcibly interrupted; these
1199
+ checks/time/memory bounds are not OS-enforced sandboxing or filesystem confinement.
1200
+ Loaded artifacts become owned display data and can be re-exported after a new review.
1201
+
1202
+ Both actual clients and private-tmux workflows verify binary save/reload, explicit
1203
+ review, private mode/no overwrite, owner fencing and no-model/draft non-mutation.
1204
+ SDK artifact_bytes/artifact_from_bytes/read_artifact expose the same validated codec.
1205
+ Artifact export/reload does not restore removed extension custom rendering, host
1206
+ mutations or terminal interception. Further MCP/credential and native-platform
1207
+ interoperability remains separate work.
1208
+
1209
+ ### Command session metadata
1210
+
1211
+ Read-only command metadata never opens or activates a session browser.
1212
+
1213
+ ### Failed extension inventory and cancellation
1214
+
1215
+ Failed/disconnected/unloaded worker registrations withdraw from the current tool
1216
+ inventory. Historical alias identities and stale-executor/argument guards remain;
1217
+ withdrawal does not authorize an old approved call or unload a mandatory validator.
1218
+ Projection settles on the owning Agent/command/child loop, including callback
1219
+ errors and cancellation. Other healthy workers/native tools remain unchanged.
1220
+ Child refreshes retain their explicit selected-tool subset. A post-hook failure
1221
+ preserves the actual tool result instead of replacing it with invented success.
1222
+
1223
+ Failure catalog updates are descriptive, owner-scoped metadata: they cannot adopt
1224
+ a different session, activate/reload a worker or approve tool execution. Old or
1225
+ foreign cached contributions never become current merely because a callback failed.
1226
+ Reload/unload remain explicit user actions; uncertain callbacks are not replayed.
1227
+
1228
+ ### Terminal command help
1229
+
1230
+ `/help` lists the current terminal command/completion menu, including UI-only
1231
+ controls and already registered extension commands. `/help QUERY` matches command
1232
+ names or descriptions case-insensitively. It does not execute callbacks, load an
1233
+ extension, submit model work or grant tool approval; availability is still checked
1234
+ when a command is actually invoked. Explicit unload/failure/menu changes appear
1235
+ on the next help request. Descriptions are inert single-line text and terminal
1236
+ controls are stripped. Oversized/invalid menus fail explicitly, never masquerade
1237
+ as a complete truncated list.
1238
+
1239
+ Help may be inspected during active work without resetting its timer or replacing
1240
+ the draft. Claw help reflects the current TUI completion snapshot, not an invented
1241
+ live runtime/catalog capability on older gateways. Use `/extensions` to refresh
1242
+ extension status explicitly. Coding's headless help retains its separate Skills
1243
+ section and also supports query filtering/known registered commands.
1244
+
1245
+ ### Registered command argument completion
1246
+
1247
+ Trusted Python commands may register an independent bounded data callback:
1248
+
1249
+ ```python
1250
+ async def complete(prefix, context):
1251
+ return [{"value": "release", "label": "Release", "description": "Argument data"}]
1252
+ api.command("deploy", "Deploy command", execute_deploy, complete=complete)
1253
+ ```
1254
+
1255
+ `runtime.command_completions()` exposes current registration identities, and
1256
+ `await session.complete_command(command, prefix, identity)` in BOTH client SDKs
1257
+ queries the corresponding worker without executing its command callback or model.
1258
+ The callback has no interactive UI/editor/navigation/session-mutation authority.
1259
+ Items are plain single-line text (32 unique entries/64 KiB result); the prefix and
1260
+ value/label/description bounds are validated on both sides. Failed/timed-out
1261
+ uncertain callbacks settle/reap their workers and withdraw current declarations;
1262
+ no retry/replay or fallback callback is implied.
1263
+
1264
+ Replacement/disposal changes the command completion identity. Stale references
1265
+ and registration changes during callback execution yield no completion data;
1266
+ an old disposer cannot remove a replacement. Both client SDK wrappers settle
1267
+ their owning Agent's tool projection if that worker fails.
1268
+
1269
+ Both interactive parent editors now query registered argument callbacks in the
1270
+ background. Suggestions replace only the cursor-local token (including its right
1271
+ suffix); quoted whitespace stays inside that token, with quotes passed literally
1272
+ rather than shell-expanded. **Tab or Enter inserts without submitting**. A subsequent
1273
+ Enter executes the typed command only through its normal command/permission path.
1274
+ Pending queries cannot turn Enter into an accidental command submission. Escape
1275
+ dismisses the suggestions and ignores their late result; Tab reopens explicitly.
1276
+
1277
+ One query is in flight plus one coalesced latest draft. Original session/context,
1278
+ command registration, full draft and cursor are revalidated before inserting.
1279
+ Changed cursor/draft/registration/connection results never overwrite the current
1280
+ editor. Claw separately negotiates `extension_argument_completion: 1`, runs the
1281
+ query under the actual idle group/worker owner, and does not activate a cold session
1282
+ or borrow the UI-command/model approval context. Previous gateways return unavailable.
1283
+
1284
+ Escape dismissal, loss of editor focus, hidden suggestions and application exit
1285
+ now signal the owned completion task immediately. One cancellation is sent per
1286
+ in-flight owner; its slot remains held until actual cleanup settles, so repeated
1287
+ Escape cannot interrupt worker reaping or launch a successor early. Uncertain
1288
+ callbacks are not replayed: their worker is reaped and current registrations are
1289
+ withdrawn; explicit reload is required if the extension remains desired. Coding
1290
+ settles its owned completion threads before retiring the extension manager at exit.
1291
+ Claw separately negotiates `extension_argument_cancel: 1` and pins cancel messages
1292
+ to the original request/connection/group/session. Older cancel-unsupported peers
1293
+ retain the bounded deadline fallback and never receive guessed cancellation.
1294
+
1295
+ Argument menus now render each supplied `label` as presentation and show its actual
1296
+ insertion `value` in brackets when they differ, alongside the description. Duplicate
1297
+ labels are allowed but duplicate insertion values are not; selection and replacement
1298
+ stay keyed to the value. Unicode/narrow layouts use the shared bounded renderer.
1299
+ Changing only a label refreshes presentation without selecting a different value.
1300
+ Unsafe/oversized label or description data rejects the entire result, not a partial
1301
+ menu. Coding reconstructs owned row copies after immutable cross-thread delivery.
1302
+
1303
+ Completion callbacks may read `context["argument_context"]` when the current
1304
+ caller supports full argument context. It is a copied dict with `arguments`
1305
+ (the captured text after the command), `cursor`, `start` and `end` (Unicode
1306
+ code-point offsets relative to that argument body). The token prefix is checked
1307
+ against `arguments[start:cursor]`; this enables later-argument suggestions based
1308
+ on preceding choices without reading the rest of a session or granting editor
1309
+ mutation authority. Host selection still replaces its original cursor-local span.
1310
+ Callback edits to this dict do not change the editor or its captured request.
1311
+
1312
+ Prefix-only SDK/legacy queries explicitly supply `None` for that context; they
1313
+ cannot impersonate a full draft. New Claw editor queries independently negotiate
1314
+ `extension_argument_context: 1`. Unnegotiated/invalid/foreign-scope metadata is
1315
+ refused before callback admission. Withdrawing support cancels captured contextual
1316
+ jobs (including before task startup), refuses late contextual output and does not
1317
+ silently replay the query as prefix-only. A user may explicitly edit/Tab to request
1318
+ new data under the remaining capability. Existing prefix-only callbacks remain
1319
+ supported; `argument_input=` is optional on both SDK wrappers.
1320
+
1321
+ More expressive suffix semantics and broader argument API interoperability remain
1322
+ open. Callback-supplied spaces/quotes are literal replacement data; the host
1323
+ never silently adds shell quoting or interprets the resulting argument. Independent
1324
+ child prompt completion is not claimed. Native file/slash-name completion is retained.
1325
+
1326
+ ### Extension terminal command-menu inspection
1327
+
1328
+ ```python
1329
+ page = await api.get_command_catalog(query="", offset=0, revision="")
1330
+ # Continue using page["next_offset"] and page["revision"].
1331
+ ```
1332
+
1333
+ A live native host may bind read-only menu inspection to an eligible owned command,
1334
+ tool, lifecycle/pre/post-tool, submitted-input or context callback. It reads the
1335
+ same sanitized terminal menu used by `/help` and completion, in 32-entry pages:
1336
+ normalized name/description, source label, session identity, revision and explicit
1337
+ pagination only. Host availability and exact invocation/session/child admission
1338
+ remain authoritative; a detached/headless or unsupported callback gets `None`,
1339
+ not another owner's menu. Independent child callbacks cannot borrow the parent's
1340
+ menu/editor. Provider/setup callbacks receive no menu control authority.
1341
+
1342
+ Worker-supplied routing/host identity is refused. The host's trusted invocation
1343
+ identity is separate from plugin request fields and carries no mutation grant.
1344
+ Changed menu/session/registration invalidates a former revision and returns
1345
+ `status="stale"`, no entries and no next page. Restart at offset zero explicitly;
1346
+ there is no silent merge, command execution, model input or automatic replay.
1347
+ Claw separately negotiates `extension_command_catalog:1` and its generation;
1348
+ old session/inspection support does not substitute for that exact bridge.
1349
+ Session/tree catalogs below retain their separately scoped read-only contract.
1350
+
1351
+
1352
+ ### Read-only extension session metadata
1353
+
1354
+ `await api.get_session_name()` returns the actual owning session's name, or
1355
+ `None` when unavailable; an empty name is not a borrowed parent value.
1356
+ `get_session`, `get_model`, `get_context_usage`, `get_active_tools` and
1357
+ `get_tool_inventory` retain bounded, owner-projected read-only data. Session/tree
1358
+ and command catalogs remain read-only; `has_pending_messages` is a boolean query,
1359
+ not a queue control API. Callback admission, role and session/child provenance
1360
+ remain checked; queries neither start a model nor grant permissions.
1361
+
1362
+ Extensions cannot read/replace the unsent editor, rename/navigate sessions,
1363
+ select tools, request compaction or enqueue prompt/context/follow-up input through
1364
+ host control APIs. Native USER `/name`, `/model`, `/compact`, `/sessions` and
1365
+ `/tools` remain independent. Business tool/provider/command/hook registration and
1366
+ basic input/confirm/select/status remain supported.
1367
+
1368
+ Claw's read-only session bridge uses `extension_session:1` and
1369
+ `extension_session_inspection:1`; terminal command-menu inspection separately uses
1370
+ `extension_command_catalog:1` and its generation. No editor/navigation/mutation
1371
+ capability or separate extension name/active-tools flag is needed. Native
1372
+ `session_name_read` and `tool_inventory_selection` controls remain independent.
1373
+ Session/tree catalogs read the bound backend directly; listing them does not grant
1374
+ plugin navigation authority.
1375
+
1376
+ ### Command session/tree catalogs
1377
+
1378
+ Interactive extension commands can now read actual host navigation metadata without
1379
+ opening a dialog or activating context:
1380
+
1381
+ ```python
1382
+ first = await api.list_sessions(query="project")
1383
+ if first is not None and first["has_more"]:
1384
+ second = await api.list_sessions(query="project", offset=first["next_offset"], revision=first["revision"])
1385
+ tree = await api.get_session_tree() # current host session
1386
+ branch = await api.get_session_tree(target_id, branch_id=branch_id)
1387
+ ```
1388
+
1389
+ Pages contain scope, owner_session, resolved tree session_id/branch_id, query,
1390
+ offset/total, at most 50 entries, has_more/next_offset and membership revision.
1391
+ Entries are inert bounded id/title/detail/kind/session/branch/checkpoint/depth/active
1392
+ metadata and safe checkpoint previews—not full hidden conversations or system
1393
+ prompts. Text/type/ID/offset/count/frame validation rejects malformed responses
1394
+ rather than coercing them. Page encoding is capped at 256 KiB, query at 1000 UTF-8
1395
+ bytes and catalog traversal at one million entries.
1396
+
1397
+ Command session pages use stable identity order, not the native browser's recency
1398
+ order, so the command's own durable entries cannot move sessions between pages.
1399
+ Pass the returned revision with continuation calls to refuse a changed membership/
1400
+ owner/query/target rather than mix catalogs. It is a membership/topology identity
1401
+ revision, NOT a frozen full-history/metadata version; previews/active flags may be
1402
+ fresh on each read. Restart at offset zero after a None refusal. Leaving revision
1403
+ empty explicitly requests a fresh current page. Native browser behavior is unchanged.
1404
+
1405
+ Coding reads the existing session-manager/tree sources off-thread under captured
1406
+ command/session context; Claw reads the owning GroupRuntime catalog, not a client
1407
+ cache or launch-directory guess. Claw tree targets remain restricted to that group.
1408
+ Host catalog operations preserve their actual filesystem owner until creation/read
1409
+ settles on cancellation, then refuse late adoption. An OS-blocked thread cannot be
1410
+ forcibly killed; these limits/ownership checks are not an OS sandbox.
1411
+
1412
+ Only actual interactive extension-worker command invocations receive catalog
1413
+ authority. Tools/hooks/context/child/unattended callbacks return None; original worker
1414
+ invocation and host extension/command/group/session ownership are independently
1415
+ checked. Missing/foreign/unreadable targets or membership changes yield unavailable
1416
+ without disabling the extension or replaying reads. Invalid plugin request/response
1417
+ codecs still fail closed. No model turn, permission/read-only mutation or session activation is introduced.
1418
+
1419
+ Real workers, both live hosts' 61-entry multi-page catalogs, search/tree/branch
1420
+ previews, revision ordering/changed membership, foreign-group refusal, cancellation
1421
+ settlement and production terminal catalog commands are verified. These catalogs
1422
+ are read-only: they do not expose the removed navigation/editor/session mutation,
1423
+ custom-rendering or terminal-interception APIs. MCP/credential/native-platform
1424
+ interoperability remains subject to its own limits.
1425
+
1426
+ ### Runtime-registered extension shortcuts
1427
+
1428
+ Trusted extensions can register a shortcut and its actual command callback:
1429
+
1430
+ ```python
1431
+ async def inspect_model(args, context):
1432
+ model = await api.get_model()
1433
+ return model["id"] if model is not None else "Model metadata unavailable"
1434
+ api.shortcut("inspect", "alt+k", "Inspect the current model", inspect_model)
1435
+ ```
1436
+
1437
+ Registration contributes the namespaced `/ext-EXTENSION-NAME` command plus a
1438
+ canonical default key; pressing it uses the EXISTING interactive command owner,
1439
+ not another tool loop or arbitrary input interception. Plugins must already be
1440
+ explicitly trusted/activated; a key does not discover/load an extension. Callbacks
1441
+ retain normal idle/child/tool-policy/session/connection checks and only the retained
1442
+ read-only command host queries and basic dialogs. No model turn or tool approval
1443
+ is implicitly created by a shortcut itself.
1444
+
1445
+ **`/keys`** lists effective extension keys and disabled conflicts. Built-in and USER
1446
+ editor bindings always win. When different extensions claim one effective key,
1447
+ ALL colliding shortcuts are disabled (manual commands remain available). Typing,
1448
+ unmodified editor/dialog keys, Escape, Ctrl+C/D/L/Z and confirmation/recovery routes
1449
+ cannot be captured. Release/repeat events cannot duplicate callback invocation.
1450
+ Registration capacity is 32 per extension/64 across active registrations.
1451
+
1452
+ The existing `keybindings.json` can remap or unbind a registered shortcut using its
1453
+ full lowercase command name, for example:
1454
+
1455
+ ```json
1456
+ {"ext-keyed-compose":"alt+x","ext-keyed-blocked":[]}
1457
+ ```
1458
+
1459
+ Multiple explicit keys may be provided as a list. Overrides still reject duplicate/
1460
+ built-in collisions and reserved routes. Configuring an inactive command does NOT
1461
+ activate a plugin; `/keys` reports it unavailable. Changes take effect when the
1462
+ client loads its keymap, like existing prompt bindings. Terminal encodings can make
1463
+ some Ctrl/Alt combinations indistinguishable from Enter/Tab; choose an unambiguous
1464
+ key or a terminal with extended keyboard support. Alt+K/Alt+X are physically tested.
1465
+
1466
+ Dispatch is confined to the ready idle prompt: approvals, extension dialogs,
1467
+ viewers, completion pickers, child/MCP panels, overlays, output reviews,
1468
+ active commands/model work and closing/disconnected owners retain priority. Unload/
1469
+ failure/reload updates registrations; stale keys cannot adopt a new callback. Coding
1470
+ now refreshes actual registration snapshots after extension commands even if a plugin
1471
+ publishes no status or notices. Claw separately advertises `extension_shortcuts: 1`;
1472
+ missing support is both dispatch-disabled and reported in effective help.
1473
+
1474
+ Real workers, both UI command/editor paths, user remap/unbind/inactive overrides,
1475
+ reserved/default/user/inter-extension conflicts, contextual suppression, repeat,
1476
+ load/reload/unload and both private-tmux default/remapped key paths are verified.
1477
+ Arbitrary terminal interception and custom renderers are removed, not pending
1478
+ shortcut features. Provider registration and read-only host queries retain their
1479
+ separate contracts; MCP/platform interoperability is not implied by a shortcut.
1480
+
1481
+ ### Submitted-input extension hooks
1482
+
1483
+ Trusted extensions can register `api.on_input(callback)` for newly admitted human
1484
+ input, before its response model call or canonical user-message commit:
1485
+
1486
+ ```python
1487
+ async def prepare(text, metadata, context):
1488
+ # metadata: prompt/steer/follow_up source, active channel and image metadata.
1489
+ if text.startswith("reject:"):
1490
+ return {"action":"reject","reason":"Explain why this input was refused"}
1491
+ return {"action":"transform","text":"Prepared input: " + text}
1492
+ api.on_input(prepare)
1493
+ ```
1494
+
1495
+ None or `{ "action": "continue" }` leaves text unchanged; a string is shorthand
1496
+ for transformed text. Explicit transform/reject objects have exact typed fields;
1497
+ unknown/handled/image/command-action payloads are NOT guessed. Text is limited to
1498
+ 1 MiB UTF-8, rejection reasons to 2000 bytes and callbacks to 32 per extension.
1499
+ Callbacks run in deterministic registration/activation order in their actual
1500
+ owned worker. Missing/malformed/failed/timed-out hook decisions refuse admission
1501
+ and quarantine the failed worker; known failed filters cannot silently pass raw
1502
+ input until explicitly unloaded/reloaded. A normal explicit rejection keeps the
1503
+ extension active. Callback side effects are not rollback and are not replayed.
1504
+
1505
+ The Agent's optional `input_transform` hook now covers initial input, identified
1506
+ steering/follow-ups and plain explicit continuation before canonical admission.
1507
+ Transforms preserve queued identity/recovery receipts: consumption happens only
1508
+ when the transformed message is committed. Rejected selected identified input
1509
+ remains recoverable with original text/images; plain rejected steering/follow-up
1510
+ messages enter an explicit-recovery quarantine (`agent.drain_rejected_messages()`),
1511
+ not a live queue that could replay them on the next prompt. Initial rejected
1512
+ input belongs to its caller, not a fabricated assistant/provider response. Hook
1513
+ cancellation is settled before idle/owner release. Preexisting Coding SDK input
1514
+ hooks are composed rather than replaced.
1515
+
1516
+ The extension API sees text plus image MIME/encoded-size metadata, never original
1517
+ base64. Its output cannot silently remove/replace images: transformed messages keep
1518
+ original typed attachments/timestamps. All later model capability, tool argument,
1519
+ approval, host read-only and child permission gates remain authoritative. A transformed
1520
+ string resembling `/quit`/a URI stays model input data, not a reparsed host command.
1521
+ Editor/session/navigation mutation authority is absent from both hook and command APIs.
1522
+
1523
+ Both interactive clients show the actual transformed user text/queued consumption,
1524
+ with visible notices. Initial refusal restores original draft/attachments without
1525
+ model input or an automatic replay. Coding uses the current worker-owned image
1526
+ batch for recovery, not a potentially lagging UI active-image pointer. Claw applies
1527
+ its existing per-connection/run input-ID normalization/fencing to transform/refusal
1528
+ receipts too. Child agents use their own extension worker/input history, not parent
1529
+ history. Claw scheduler/goal/system initial inputs are explicitly NOT human input
1530
+ hooks; queued human steering/follow-up remains intercepted. Channel metadata is the
1531
+ active turn channel, not a claim of a separate queued sender's identity.
1532
+
1533
+ Real workers, generic initial/steer/follow-up/continuation/abort receipts, both live
1534
+ clients' typed attachments/canonical history/refusal/recovery, actual queued follow-up
1535
+ images/consumption, child isolation/system exclusion and private-tmux transform/
1536
+ refusal recovery are tested. Submitted-input transformation and the handled outcomes
1537
+ below remain supported; neither exposes raw-key observation/interception, custom
1538
+ rendering or host mutations. MCP/credential/native-platform interoperability remains
1539
+ subject to its own limits.
1540
+
1541
+ Pre-turn compaction of PREVIOUS history retains its existing lifecycle; the input
1542
+ hook is a pre-admission/user-response check, not a veto of independent maintenance
1543
+ work. Failed reload of a previously registered input filter remains failed/required,
1544
+ not an implicit unload: only successful reload or explicit unload changes that
1545
+ policy. Print mode reports a refused input as a nonzero error. No synthetic assistant answer is fabricated.
1546
+
1547
+ Terminal verification also caught a generic resize race during output review:
1548
+ painting after dimensions changed during tick callbacks could skip the next loop's
1549
+ cursor query. That paint is now deferred until the normal input loop re-anchors.
1550
+ Existing visible-confirmation/query assertions were retained, not weakened.
1551
+
1552
+ ### Explicit handled-input outcomes
1553
+
1554
+ Submitted-input hooks may now return an explicit handled decision with bounded
1555
+ feedback, for example:
1556
+
1557
+ ```python
1558
+ if text.startswith("local-help:"):
1559
+ return {"action":"handled","feedback":"Extension handled this request; no model answer was generated"}
1560
+ ```
1561
+
1562
+ Feedback is required, nonempty and at most 64 KiB UTF-8; extra image/command/action
1563
+ fields are rejected. Handled is NOT rejection and NOT canonical/model history
1564
+ admission. It stops the remaining input-hook chain for that request and emits a
1565
+ separate `InputHandledEvent` logical-consumption receipt with original source/ID/
1566
+ attachments. Identified inputs are removed exactly once; they do not also emit
1567
+ InputConsumedEvent or return for automatic replay. SDK callers can inspect/drain
1568
+ handled receipts with `agent.drain_handled_inputs()`.
1569
+
1570
+ If all newly supplied input is handled, the host does not invoke the response model
1571
+ with old history just to obtain an answer. Other genuinely queued unhandled requests
1572
+ may still run normally, preserving ONE_AT_A_TIME steering boundaries. Explicit
1573
+ `agent.prompt([])` retains its preexisting old-context continuation semantics: it
1574
+ contains no submitted request to intercept. If one request is handled and a later
1575
+ request rejects/fails, the handled receipt remains committed rather than falsely
1576
+ rolled back; remaining original input stays recoverable. Trusted callback side
1577
+ effects are not an OS sandbox or rollback transaction.
1578
+
1579
+ Original image bytes are never given to the hook, and handled decisions cannot
1580
+ silently discard attachments. Both interactive clients retain them in the editable
1581
+ composer without restoring/replaying the consumed text. Queue/run/connection ID
1582
+ fences apply to the handled receipt too. Feedback is labelled system/extension data,
1583
+ not fabricated assistant prose or tool approval. Permission, host read-only, tool and model
1584
+ capability gates are unchanged; returned command-looking feedback is never executed.
1585
+
1586
+ Print mode outputs explicit feedback and returns success for handled-only input;
1587
+ JSON mode emits a valid system/input_handled envelope (optional real assistant output
1588
+ is separate), not a counterfeit model message. Claw sends a content-free final
1589
+ signal after actual handled feedback, releasing run ownership without synthesizing a response. Other
1590
+ non-TUI channels receive extension feedback as channel output, not model generation.
1591
+
1592
+ Child supervision retains labelled input feedback as separate bounded metadata
1593
+ (64 entries/64 KiB), with zero model calls when the task is handled. It survives child
1594
+ record reload and appears as SYSTEM feedback in source inspection, not invented
1595
+ user/assistant history. Parent conversations remain unchanged. New shipped clients
1596
+ are jointly verified; older-viewer handled-outcome interoperability remains unproven
1597
+ rather than being inferred from JSON accepting extra event types.
1598
+
1599
+ Generic initial/queued/old-history/queue-mode receipts, both live initial and queued
1600
+ image paths, child result/source metadata, text/JSON completion and production
1601
+ terminal model-call counters are tested. Plugin terminal key/paste/release
1602
+ interception and observation APIs are removed, as are custom renderers and extension
1603
+ host mutations. Handled outcomes preserve the ordinary permission and ownership
1604
+ boundaries; remaining MCP/credential/platform interoperability is separate.
1605
+
1606
+
1607
+ ### MCP browsing and manual refresh
1608
+
1609
+ Active resource/catalog/combined notification watches are removed from the SDK,
1610
+ transports and native UI. There are no watch/unwatch methods, editable subscription
1611
+ filters, watch jobs or background subscription listeners. Former **w** resource
1612
+ watch and **Alt+T/P/U/W** catalog/combined controls are not supported.
1613
+
1614
+ Ordinary MCP tools, resource/prompt catalogs, explicit reads/completions and manual
1615
+ refresh remain. Passive tool-catalog invalidation on supported legacy notices only
1616
+ marks cached definitions dirty; it does not fetch a catalog/resource, register tools
1617
+ or start a model turn. Configured Roots and exact request-state continuations,
1618
+ response-scoped SSE, cancellation and bounded legacy GET recovery remain separate
1619
+ transport features. They never authorize uncertain tool POST replay or automatic
1620
+ reconnect. Normal MCP chat/tool traffic and private extension-worker JSON-RPC are
1621
+ not removed by this simplification.
1622
+
1623
+ ### Explicit saved MCP OAuth credentials
1624
+
1625
+ Completed resource-bound OAuth grants can now be saved **only after a separate
1626
+ reviewed confirmation**. In the authorization status view, **p** prepares save.
1627
+ From the MCP server list, **l** prepares explicit restore and **x** prepares
1628
+ saved-credential erase. Every action pages the issuer/resource/client/scopes/endpoints,
1629
+ TLS trust, destination and storage disclosure before Enter becomes available.
1630
+ No token/code/secret paste counts as consent; old or detached receipts cannot commit.
1631
+
1632
+ The default `mcp_credential_backend: "file"` stores a **private local plaintext
1633
+ JSON file, not encrypted/keychain storage**.
1634
+ Coding uses its user data directory's `mcp-credentials`; Claw uses the group's
1635
+ private data directory. This implementation requires verified local POSIX ownership
1636
+ and 0700-directory/0600-file permissions. Unsupported platforms and unsafe paths,
1637
+ symlinks, hard links, ownership/mode/type/size violations fail closed rather than
1638
+ claiming equivalent protection. Credential filenames are resource hashes; writes
1639
+ are bounded, fsynced and atomically replaced through pinned directory-relative I/O.
1640
+
1641
+ Nothing loads at startup. Explicit restore validates exact resource, configured
1642
+ issuer/pre-registered client/public method/scopes,
1643
+ certificate-file content binding and expiry, then admits the credential to memory.
1644
+ It performs no metadata lookup, token POST, connection, model turn or tool grant.
1645
+ MCP client-secret methods are not supported; provider credentials remain a
1646
+ separate worker/vault contract. Access/refresh credentials have
1647
+ no public diagnostic representation and never enter transcripts or review payloads.
1648
+
1649
+ Saved access expiry uses bounded wall-clock values and is converted back to an
1650
+ in-memory deadline on restore. Expired access can preserve its saved refresh grant,
1651
+ but refresh still needs its own live reviewed action. Before a potentially rotating
1652
+ refresh POST, an existing saved snapshot is removed, so restart cannot replay an
1653
+ old refresh token after uncertain rotation. Rotated credentials are **not** saved
1654
+ implicitly; explicitly review/save the new grant if desired.
1655
+
1656
+ **x** erases the saved credential only (not a live token or remote grant). The existing
1657
+ authorization-status **f** forget/disconnect review erases both memory and saved
1658
+ state; neither action
1659
+ claims remote revocation. Save/erase cancellation revokes storage admission and waits
1660
+ for the actual writer to settle; if an operation committed before cancellation,
1661
+ inspect local state rather than automatically retrying it.
1662
+
1663
+ SDK callers can opt in with `McpManager(..., credential_dir=...)` and prepare/confirm
1664
+ `credentials_save`, `credentials_restore`, or `credentials_forget` through the
1665
+ existing owned `manage_auth` API. A manager without a credential directory remains
1666
+ memory-only. Actual client restart/consent and private-tmux tests cover the file
1667
+ backend. File permissions are not an OS sandbox.
1668
+
1669
+ #### Opt-in Linux Secret Service storage
1670
+
1671
+ Set `"mcp_credential_backend": "secret-service"` in your global
1672
+ `~/.config/xdog/coding/settings.json`. Project and session settings cannot override
1673
+ this global storage choice. The default remains `"file"`.
1674
+
1675
+ SDK hosts select `McpManager(..., credential_dir=..., credential_backend="secret-service")`.
1676
+ The directory is used only to derive a stable namespace; this backend creates no
1677
+ local token files. Moving that directory changes which saved credentials are found.
1678
+
1679
+ Prerequisites are Linux, `/usr/bin/python3` with OS-provided GI bindings and the
1680
+ Secret 1/libsecret typelib, an existing `DBUS_SESSION_BUS_ADDRESS`, and an
1681
+ **already running Secret Service with an unlocked default collection**. XDOG does
1682
+ not install prerequisites, start the vault, create a collection, unlock it or
1683
+ launch an authorization prompt. Unlock your vault externally before storage actions.
1684
+ An encrypted Secret Service session is required; at-rest protection is supplied
1685
+ by your vault, not guaranteed by XDOG.
1686
+
1687
+ The same explicit save/restore/forget reviews apply, with a **NATIVE SECRET SERVICE**
1688
+ storage notice. No startup restore or implicit save is added. Invalid backend names,
1689
+ missing prerequisites, locked/ambiguous records and malformed data refuse without
1690
+ falling back to plaintext files or initiating login. The owned helper has a bounded
1691
+ 10-second operation timeout; cancellation terminates and reaps it. A mutation that
1692
+ was already admitted may have committed: inspect the vault before retrying; XDOG
1693
+ never automatically replays an uncertain mutation.
1694
+
1695
+ Tests cover actual encrypted save/read/forget, locked-vault refusal, manager
1696
+ restart/consent and both application UI owners against an isolated owned GNOME
1697
+ keyring service, plus helper timeout/cancellation. This is not a native-backend
1698
+ tmux test or proof of every Secret Service implementation. Credential storage is
1699
+ Linux-only: `file` and `secret-service` are the supported choices. Removed native
1700
+ backend names are rejected without reading credentials or silently selecting file
1701
+ storage. Neither Linux backend is an OS sandbox; broader service interoperability
1702
+ is not implied by the isolated service tests.
1703
+
1704
+
1705
+ ### Session-owned extension providers
1706
+
1707
+ Explicitly trusted extensions can declare provider callbacks during setup:
1708
+
1709
+ ```python
1710
+ def setup(api):
1711
+ async def stream(model, context, options):
1712
+ yield {"type": "text", "text": "local response"}
1713
+ yield {"type": "done", "stop_reason": "stop"}
1714
+ api.register_provider("local", [{
1715
+ "id": "example", "name": "Example", "context_window": 32000,
1716
+ "max_tokens": 2048, "supports_tool_calls": False,
1717
+ }], stream)
1718
+ ```
1719
+
1720
+ Activate the extension explicitly, inspect `/model`, then select its full alias
1721
+ `ext-EXTENSION-PROVIDER/MODEL`. Registrations belong to that session's owned worker,
1722
+ not the global AI provider registry; aliases cannot replace built-in names. Context,
1723
+ input modalities, reasoning/tool flags, output bounds and optional pricing are
1724
+ validated cached metadata. Catalog inspection starts no model request. Explicit
1725
+ configured/saved alias activation and provider authentication are documented below;
1726
+ neither permits implicit login or another provider's fallback.
1727
+
1728
+ The callback receives lossless JSON context/options through a bounded checksummed
1729
+ transfer. It returns an async iterator of typed `text`, `thinking`, `tool_call`,
1730
+ `usage` and explicit `done` events. Adjacent text/thinking chunks coalesce by default,
1731
+ with the latest continuity signature; `new_block: true` starts a separate block.
1732
+ Tool calls are data routed through the SAME existing agent validation/permission
1733
+ loop, never executed by a provider event. Calls not offered in the actual context,
1734
+ duplicate IDs, malformed/nonfinite data, quota violations and missing completion
1735
+ fail rather than granting authority or using a fallback provider.
1736
+
1737
+ Four registrations/extension, 32 models/registration, 64 session models, 4,096 stream
1738
+ events and 8 MiB emitted content bound this callback path. Output options are capped
1739
+ by declared model limits. Only one owned stream/input transfer runs per worker.
1740
+ Provider callbacks cannot borrow dialogs/editor/session/command authority. Cancel
1741
+ settles the actual in-flight worker RPC; uncertain callbacks are quarantined/reaped,
1742
+ not replayed. Unload/reload/close generations fence results and make the explicit
1743
+ alias unavailable rather than silently routing to a built-in.
1744
+
1745
+ Child model overrides use the independently created CHILD extension worker and
1746
+ retain existing child context/vision/reasoning/budget guards and parent tool
1747
+ restrictions; selecting a child provider does not switch the parent's model.
1748
+ Existing primary routing and native/global provider registration are unchanged.
1749
+ Owned worker/client/child and production Linux/private-tmux model-selection paths
1750
+ verify this behavior without paid model calls. Additional native/embedding/search/
1751
+ provider interoperability and native-platform validation remain separately bounded;
1752
+ explicit callback authentication and vault storage are described below.
1753
+
1754
+
1755
+ ### Explicit extension provider OAuth and retained vault storage
1756
+
1757
+ Trusted provider declarations can retain a private `ProviderOAuth` binding through
1758
+ `api.register_provider(..., oauth=...)`. Login/refresh/key/model callbacks execute
1759
+ inside the owned extension worker; credentials and callback objects are not public
1760
+ catalog/UI data. Generic `ProviderAuth` bindings remain separate. These provider
1761
+ callbacks are not MCP registration methods or an Elicitation capability.
1762
+
1763
+ Both native hosts expose `/extensions auth list` or `menu`, explicit `login ID`,
1764
+ `refresh ID` and `logout ID`, plus `/login [EXTENSION_PROVIDER_ID]` as a thin
1765
+ selection/login alias. Every operation requires its original idle session/provider
1766
+ registration and a separate owned review; URL opening is a distinct reviewed user
1767
+ gesture, never automatic. Sensitive replies go only to the original worker, not
1768
+ model history or a replacement question. Cancellation/reload/disconnect retires
1769
+ that owner without automatic callback replay. Login/refresh does not grant tools,
1770
+ select a model or change permissions. Logout clears worker memory, not saved data.
1771
+
1772
+ Provider-defined OAuth callbacks are independent of MCP's public-PKCE profile.
1773
+ Env/resolver credentials remain private and lazy. A grant that expires while an
1774
+ async key callback is suspended cannot admit a business stream; failure does not
1775
+ silently log in, refresh, replay a callback or choose another provider.
1776
+
1777
+ Provider credential persistence is retained through explicit
1778
+ `/extensions auth save ID secret-service /ABSOLUTE/NAMESPACE`, with equivalent
1779
+ `restore` and `forget` actions. This is **Linux Secret Service vault only**, with
1780
+ an explicit backend/absolute namespace and provider source/profile binding. It
1781
+ shares the owned helper's no-start/no-unlock, cancellation/receipt and no-replay
1782
+ protections. No automatic save/restore/login occurs; missing/locked/unsafe vaults
1783
+ refuse. There is **no plaintext file fallback** for provider credentials. MCP's
1784
+ separately selected `file` or `secret-service` credential backend does not change
1785
+ this provider-vault contract.
1786
+
1787
+
1788
+ ### Configured and saved extension-model activation
1789
+
1790
+ Configured or saved `ext-EXTENSION-PROVIDER/MODEL` aliases now activate their
1791
+ explicitly trusted extension workers before readiness/first use. They do not go
1792
+ through unresolved-model fallback and are not rewritten to a built-in model.
1793
+ Untrusted/missing/failed declarations fail explicitly and release bootstrap owners.
1794
+ Metadata activation invokes no provider callback or model request.
1795
+
1796
+ Coding's synchronous SDK factory also works when called from an existing async
1797
+ loop, using one owned metadata bootstrap rather than nested event-loop execution.
1798
+ CLI `--model`, saved resume (`--resume-id`/session selection), and in-session saved
1799
+ activation restore the declared limits, tool/image metadata and normalized reasoning
1800
+ choice. New runtime activation occurs once; ordinary explicit unload is never an
1801
+ implicit reload. Bootstrap errors are reported cleanly by the CLI.
1802
+
1803
+ Claw activates configured aliases before its owned gateway reports readiness. Its
1804
+ explicit model selection is saved atomically in a session-owned model sidecar;
1805
+ restart/resume restores that alias and the corresponding worker/limits. Selection
1806
+ persistence completes before the live model is changed. Invalid/symlinked/excessive
1807
+ saved model files or unavailable trusted registrations fail, not choose a primary
1808
+ provider. Image metadata comes from the active extension registration, not a global
1809
+ catalog guess. Existing primary-provider routing is unchanged.
1810
+
1811
+ Owned SDK/actual socket/restart tests and production Linux/private-tmux startup and
1812
+ resume paths verify zero built-in/model calls during activation and correct first
1813
+ provider use/native recovery. This supersedes the earlier initial-alias activation
1814
+ exclusion. Additional dynamic/native/provider-auth and host APIs, interoperability
1815
+ and native-platform validation remain on their original open audit rows.
1816
+
1817
+
1818
+ ### Configured tool browser
1819
+
1820
+ **`/tools [QUERY]`** opens a read-only browser of the actual owning Agent's
1821
+ configured tool names, descriptions and full JSON schemas. Search includes names,
1822
+ descriptions and schema text—not just the visible viewport. `/`, n/N, arrows/pages,
1823
+ selection and **f** full-height viewing reuse the existing source browser;
1824
+ **r** explicitly refreshes and Escape returns to the unchanged parent draft/cursor.
1825
+ Copy/export/share use the captured tool-definition records, never conversation
1826
+ history as a fallback. Existing explicit output review/private-storage policy applies.
1827
+
1828
+ The summary separates configured definitions from the model API gate and explicitly
1829
+ states that listing a tool is NOT execution approval. Unsupported/text-only models
1830
+ can inspect their local definitions without sending API tools. Browsing does not
1831
+ execute or enable tools, register MCP/extension definitions, or submit model input.
1832
+ Snapshot refresh is explicit, not automatic during a run.
1833
+
1834
+ Coding reads metadata on one bounded background worker; its headless `/tools` command
1835
+ prints complete, query-filtered JSON without truncating the first inventory page.
1836
+ Claw separately negotiates `tool_inventory:1` and reads the gateway's actual group/
1837
+ session Agent, with request correlation, cancellation, timeout, capability withdrawal
1838
+ and session-owner invalidation. Cold inspection may initialize the group's local
1839
+ session cache and returns its actual session ID, but performs no model/tool turn or
1840
+ idle/daily reset. Older gateways report unavailable—no client footer/schema guess.
1841
+
1842
+ Full definitions remain bounded by the existing 2,048-tool/512-KiB inventory limit.
1843
+ Unavailable/invalid/changing owners are reported explicitly rather than displayed
1844
+ as an empty or approved tool set. Definitions are public model-facing data; authors
1845
+ must not place credentials in schemas. This is Linux/private-tmux evidence, not
1846
+ complete CLI capability parity or every Linux desktop terminal.
1847
+
1848
+ ### Explicit context compaction
1849
+
1850
+ Use `/compact [focus instructions]` to summarize older conversation context while
1851
+ retaining a complete recent user turn, including its tool exchanges. The optional
1852
+ focus is limited to 16 KiB. The summary uses the **selected session model adapter**
1853
+ (including registered extension providers), not a primary-provider fallback, and
1854
+ its request exposes no tools. Current model context/prompt limits determine the
1855
+ retained history budget. Too little safely separable history is an explicit no-op.
1856
+
1857
+ Compaction requires an idle session and idle children. The editor draft and existing
1858
+ permission mode remain unchanged. Empty, incomplete, canceled, or failed summaries
1859
+ are not substituted into history, and a persistence failure is not reported as
1860
+ successful compaction. Access and extension metadata owners retain the compacted
1861
+ history for subsequent writes.
1862
+
1863
+ In the TUI, Escape or `/compact cancel` cancels an active compaction command. Once
1864
+ an atomic history commit has been admitted, cancellation settles that disk write
1865
+ and in-memory publication rather than pretending to roll it back. If cancellation
1866
+ or disconnection loses a receipt, inspect `/transcript` before retrying; the command
1867
+ is not automatically replayed. Native scrollback remains the record of what was
1868
+ previously displayed, while the transcript viewer can read the current context.
1869
+
1870
+ Trusted extensions may observe, veto, or provide a summary through
1871
+ `api.on("session_before_compact", callback)`, and observe committed context through
1872
+ `api.on("session_compact", callback)`. This applies to manual and automatic
1873
+ compaction; callbacks receive complete typed preparation rather than a UI preview.
1874
+ Custom summary boundaries must preserve complete recent user/tool turns. Bounded
1875
+ source/details metadata persists with the session and its branches. Hook callbacks
1876
+ cannot borrow command/dialog/navigation authority or change permissions through
1877
+ compaction results; see the Agent package's compaction extension contract.
1878
+
1879
+ ### Recovering context before compaction
1880
+
1881
+ Every successful manual or automatic compaction now saves a named **Before
1882
+ compaction #N** checkpoint containing the complete original typed history. The
1883
+ checkpoint and shortened active context are stored in one atomic session write;
1884
+ failed saves cannot publish a shortened context without its recovery data.
1885
+ Compaction does not automatically activate the checkpoint or change permissions.
1886
+
1887
+ Open `/tree`, search for `Before compaction`, and select the checkpoint to restore
1888
+ its conversation. Restoration retains a return checkpoint of the compacted head,
1889
+ so it is reversible. The existing transcript viewer can then search/copy/export
1890
+ that restored full history. This changes conversation context, not workspace files;
1891
+ restoration still requires an idle owner and preserves the normal permission mode.
1892
+ An incomplete tool-call tail is retained in recovery data but cannot be resumed
1893
+ as a complete branch: drill into the tree and choose an earlier valid checkpoint.
1894
+
1895
+ Checkpoint records retain model/settings, read-only state, extension entries, and
1896
+ prior compaction metadata. Committed compaction metadata and extension post-events
1897
+ also carry an optional `recovery_branch_id` linking to that original preparation.
1898
+ Repeated compactions keep separate checkpoints rather than replacing the old one.
1899
+
1900
+ ### View saved context without activating it
1901
+
1902
+ In `/sessions` or `/tree`, select a saved session/branch and press **v** to open a
1903
+ read-only source viewer. **Enter** remains the separate activation action. You can
1904
+ also use:
1905
+
1906
+ ```text
1907
+ /transcript branch BRANCH_ID
1908
+ /transcript saved SESSION_ID [BRANCH_ID]
1909
+ ```
1910
+
1911
+ The viewer searches full saved text, reasoning, and tool input/output—not only
1912
+ navigation previews. It does not resume the saved conversation, call a model/tool,
1913
+ change the active branch, or modify the parent draft. Binary bodies/signatures are
1914
+ not displayed, and normal source redaction applies. Current-session entries without
1915
+ a branch open the ordinary live viewer; other saved sessions use persisted source.
1916
+
1917
+ Refresh explicitly with **r** or `/transcript refresh`; **f** toggles fullscreen.
1918
+ Copy/export/share uses the displayed saved snapshot and the existing reviewed output
1919
+ workflow, never the live conversation as a fallback. Loading/failed/retired reads
1920
+ cannot be copied or exported. Closing returns to the existing draft; reopening
1921
+ `/transcript` without a saved selector opens current source again.
1922
+
1923
+ ### Model selection uses the owning adapter
1924
+
1925
+ `/model` lists canonical streaming-chat IDs from the same session adapter that
1926
+ executes requests, including active registered extension providers. It does not
1927
+ assemble a second catalog from the global AI runtime. Explicit selection resolves
1928
+ through that adapter and persists the canonical ID before publishing model,
1929
+ context/prompt limits, tool/vision metadata, and effective reasoning settings.
1930
+
1931
+ Unavailable, non-chat, non-streaming, or invalid cached profiles are refused without
1932
+ switching the active model. Unsupported advertised reasoning efforts are not
1933
+ silently substituted; select a supported effort or `off`. Selecting a model that
1934
+ does not advertise reasoning clears the effective effort. Failed setting saves
1935
+ leave model/options/settings/capabilities unchanged. Native saved-session/branch
1936
+ profile and effort checks run before current context and owned resources are replaced.
1937
+
1938
+ Startup/resume no longer silently substitutes the first model for a missing requested
1939
+ or saved native profile. With no configured model, default selection must find a real
1940
+ streaming-chat profile; an empty catalog is an error, not a guessed `sonnet` request.
1941
+
1942
+ An explicitly supplied SDK stream function without model metadata remains an opaque,
1943
+ caller-owned adapter. Its explicit IDs/options can be delegated to that function,
1944
+ but selection does not borrow capability claims from the global runtime or the
1945
+ previous model: model/vision metadata stays unavailable, tool support is unreported,
1946
+ and context estimates use the documented host fallback rather than a claimed profile.
1947
+ Extension aliases still require their active, explicitly trusted worker declaration.
1948
+
1949
+ ### Prepare saved extension providers before navigation
1950
+
1951
+ Resume and branch restoration now prepare trusted extension workers against the
1952
+ target workspace, settings, read-only state, and saved extension entries **before**
1953
+ replacing the current conversation or its resource owners. A saved provider alias
1954
+ must be declared by that prepared target runtime; the current runtime's catalog is
1955
+ not used as a substitute. Declared effort/capability checks still apply.
1956
+
1957
+ Preparation has no UI/dialog/navigation lease and buffers host-managed entry writes.
1958
+ A missing provider, failed activation, unsupported effort, canceled preparation, or
1959
+ failed target save leaves the current session/Agent context, extension workers,
1960
+ MCP manager, children, read-only owner, permission mode, and draft intact. Buffered
1961
+ setup entries are not written into the saved target on failure. Successful activation
1962
+ adopts the prepared workers once, binds their entries/inspection to the live owner,
1963
+ and publishes model/history/settings together after the atomic target save. Branch
1964
+ activation retains a return checkpoint in that same committed session snapshot.
1965
+
1966
+ Callbacks receive `context["staged"] == True` during preparation. This is an
1967
+ informational lifecycle flag, not a permission grant. Extension code is explicitly
1968
+ trusted code with the process user's permissions: arbitrary filesystem/network or
1969
+ other external side effects cannot be rolled back by the host. Only host-managed
1970
+ entries/session publication is buffered. The synchronous SDK uses one owned bootstrap
1971
+ thread rather than nesting `asyncio.run`; the interactive main terminal loop stays
1972
+ responsive. Cancellation before commit discards the stage; a commit already admitted
1973
+ to atomic storage may complete, so inspect current state before retrying a lost receipt.
1974
+
1975
+ ### Exact slash-command submission
1976
+
1977
+ Enter submits a completely typed registered slash command as written, even when
1978
+ completion also offers a longer name—for example, `/session` does not become
1979
+ `/sessions`, and `/ext-demo-show` does not become `/ext-demo-shows`. Matching is
1980
+ case-insensitive, like command dispatch. Suggestions may still be browsed with
1981
+ Up/Down and explicitly accepted with Enter, or inserted with Tab; incomplete-prefix
1982
+ completion keeps its existing behavior.
1983
+
1984
+ Editing, history changes, and catalog changes clear prior neighbor-selection intent.
1985
+ A command withdrawn while it is being typed is not silently reinterpreted as a
1986
+ neighbor; the dispatcher reports its availability normally. A stale withdrawn
1987
+ suggestion is not submitted. File/path completion remains separate: selecting a
1988
+ file still inserts a reference without submitting a conversation.
1989
+
1990
+ ### Search the session's combined history graph
1991
+
1992
+ Use `/transcript timeline [SESSION_ID]` to view the current context and every saved
1993
+ branch of that session together, without activating a branch or sending a model turn.
1994
+ The normal full-source search, fullscreen, selection, and reviewed output workflow
1995
+ remain available. Current-session head data is captured from the admitted live Agent
1996
+ history; inactive sessions use persisted data. Refresh explicitly to capture updates.
1997
+
1998
+ This is a provenance graph, not a guessed timestamp chronology. Records shared by a
1999
+ recorded parent prefix or a verified compaction recovery link appear once and list
2000
+ all contributing source labels/IDs. Different roots, repeated later turns, divergent
2001
+ forks, changed protocol/model/content, and different tool results stay distinct even
2002
+ when their visible text happens to match. Compaction-retained history must match its
2003
+ original checkpoint before it can share identity; mismatched links fail the read,
2004
+ never silently omit content. Binary/signature payloads are not displayed, but their
2005
+ raw identity participates in lineage checks; normal source redaction applies.
2006
+
2007
+ Capacity failures report unavailable rather than exporting a clipped graph: at most
2008
+ 256 sources including the head, 20,000 messages per source, 200,000 raw references,
2009
+ and 20,000 unique formatted records. Inspect individual branches when that capacity
2010
+ is exceeded. The viewer leaves active context, permissions, branch and draft unchanged.
2011
+
2012
+ ### Complete rendered-context image admission
2013
+
2014
+ The shared Agent loop now checks typed images in the **actual rendered Context**
2015
+ after configured context hooks/message conversion and before every model adapter
2016
+ request. Retained user images, tool-result images and explicitly hook-added images
2017
+ all count against available model image limits. The validator never prunes images
2018
+ or silently converts them to text to make a request succeed. Rejection retains
2019
+ canonical messages/tool results and produces an explicit error.
2020
+
2021
+ Metadata comes only from the configured stream adapter's cached `resolve_model`
2022
+ interface; registered providers use the same contract. Declared positive count,
2023
+ byte and media limits and advertised image input are enforced. This does NOT apply
2024
+ the four-new-attachment composer cap to a model advertising a larger whole-context
2025
+ limit. Unspecified byte limits use the existing neutral 32 MiB payload safety bound,
2026
+ not an invented vendor limit. Base64/typed MIME checks are not a complete raster
2027
+ decoder or a guarantee of provider wire-format conformance.
2028
+
2029
+ Validation runs off the asynchronous loop. Recheck the same adapter's image profile
2030
+ after validation: changed/disappeared/malformed metadata refuses the request,
2031
+ without guessing successor limits or replay. A cooperative abort during validation
2032
+ also prevents the adapter request after byte checks settle.
2033
+
2034
+ Opaque SDK streams (or transparent wrappers returning no metadata) remain
2035
+ caller-owned: the validator does NOT borrow another/global provider's catalog or
2036
+ claim that unknown limits passed. Such callers need to supply their own capability
2037
+ contract/validation. Native/registered metadata-backed app paths are exercised;
2038
+ unknown-provider/raster/native-platform interoperability remains open.
2039
+
2040
+ ### Read-only child input inspection
2041
+
2042
+ The child roster's **q** (or **Ctrl+Q** from its transcript view) opens a bounded
2043
+ snapshot of the owning child's pending inputs or stopped recovery metadata.
2044
+ **Up/Down** selects a row, **Enter** inspects its full metadata, **r** explicitly
2045
+ refreshes, and **Escape** returns. Delivery lane, checkpoint selection, attachment
2046
+ count and `initial-task`/`crash-snapshot`/`durable-return` uncertainty are visible.
2047
+ This native view has no editor, reorder/remove/return control, recovery-copy button
2048
+ or permission-confirmation action. Paste cannot submit or adopt a draft.
2049
+
2050
+ The ordinary main-Agent `agent_control` tool retains `action="queue"` with a typed
2051
+ JSON `text` request. SDK `ChildSupervisor.control("queue", ...)` also remains.
2052
+ Their edit/remove/move/text-return and explicit stopped recovery operations use the
2053
+ real owner loop and existing identity, revision, selected-input, image-byte and
2054
+ write-before-publication safeguards. They are not native UI actions and do not
2055
+ bypass the host's normal tool policy or host read-only scope.
2056
+
2057
+ Claw's `child_queues:1` now exposes list-only native inspection. Native queue packets
2058
+ other than `{"action":"list"}` and retired recovery/binary-transfer packets are
2059
+ refused before backend mutation or image work. No capability implies queue-writing
2060
+ authority. Necessary child cancel/wait/lifecycle controls remain separate.
2061
+
2062
+ ### Explicit stopped-child recovery through Agent/SDK
2063
+
2064
+ After a child settles, only identified inputs not admitted to canonical history
2065
+ are retained with its durable record; consumed follow-ups are not offered again.
2066
+ Loading records does not construct an Agent or restart work. Malformed, duplicate,
2067
+ oversized or invalid typed attachments refuse load rather than silently disappear.
2068
+ Existing bounds remain 32 inputs, 16 KiB text each and bounded aggregate/record/image
2069
+ retention. Persistence failure is visible, not a truncated success receipt.
2070
+
2071
+ The native **q** view is inspection only. Explicit main-Agent/SDK queue action
2072
+ `recover` uses the original child/input ID and queue revision to return a
2073
+ non-destructive text copy; `recover_images` handles typed image copies, and
2074
+ `recover_task` handles an unadmitted initial task. A lost/canceled copy receipt
2075
+ cannot erase the durable source or automatically resubmit it. `remove`/`remove_task`
2076
+ are distinct explicit discard operations, persisted before publishing removal;
2077
+ cancellation waits for actual writer settlement, without claiming rollback.
2078
+
2079
+ The main-Agent tool returns image parts as `ImageContent` with bounded receipt
2080
+ metadata, never raw base64 in model-facing text or a silently lossy text fallback.
2081
+ An embedder owns later adoption/submission and its policy. Inspect prior history
2082
+ and workspace effects before deciding whether to run a recovered copy.
2083
+
2084
+ ### Child rendered-image admission
2085
+
2086
+ Child requests now validate the **complete rendered image context** even when the
2087
+ child uses the parent's default model or only overrides thinking. This includes
2088
+ retained user/tool images and images added by context hooks. The final guard
2089
+ resolves the actual child adapter's current model metadata, checks streaming-chat
2090
+ and image capabilities, image-count/byte/media limits and typed base64 payloads,
2091
+ and refuses a model profile change during admission before calling the adapter.
2092
+ A withdrawn model is not revived from the earlier selection snapshot. Metadata-less
2093
+ custom adapters remain supported for text, but cannot send a child image context
2094
+ without an advertised model profile; no images are silently converted to text.
2095
+
2096
+ Retained-context counts use the advertised model limits, **not** the four-image
2097
+ composer limit. Unspecified counts do not impose that per-draft limit on retained
2098
+ history. Existing neutral payload and child transcript/persistence budgets remain
2099
+ in force. Offline tests cover both actual application child factories, retained
2100
+ user/tool images and a real owned context-hook worker. Existing private-terminal
2101
+ child approval/recovery checks are separate compatibility evidence, not an image
2102
+ attachment UI test. Native child start/steering/follow-up image drafts and typed submission are
2103
+ implemented below. Image queue return/stopped recovery and remaining draft
2104
+ retention/rendering/transport requirements stay OPEN.
2105
+
2106
+
2107
+ ### Reviewed child image drafts
2108
+
2109
+ The native child editor now supports real image attachments for **start**, **steer**
2110
+ and **follow-up**. In a child task form, **Ctrl+O** opens a literal file-path entry
2111
+ (relative to the workspace); **Ctrl+V** explicitly reads the clipboard;
2112
+ **Ctrl+B** opens the child attachment list (Enter previews, x removes, c clears).
2113
+ These controls act on the child draft only. The parent text, cursor and attachments
2114
+ are not borrowed or changed. File/clipboard reads run outside the UI loop, and
2115
+ images stay editable until a separately painted confirmation review.
2116
+
2117
+ The review pages the task, access, configuration, image identity/dimensions/size
2118
+ and SHA256 digest. Every page must be painted before physical Enter can admit
2119
+ work; pasted newlines/repeated or unpainted Enter cannot confirm. Image-only tasks
2120
+ and image-only steering/follow-ups are supported. Successful admission clears the
2121
+ child draft only after the actual owner returns matching text, image digests and
2122
+ MIME types. Missing/mismatched/failed receipts retain the exact draft; an uncertain
2123
+ receipt is disclosed again on reopening. Reopening never automatically submits.
2124
+
2125
+ The normal input limits are four PNG/JPEG/WebP images per draft, 10 MiB each.
2126
+ Editor retention is shared with other local attachments; the child runtime has
2127
+ its own 40 MiB retained-image and serialized-collection guards. Images no longer
2128
+ consume the 512 KiB **text/metadata** transcript budget. Initial images are saved
2129
+ before child execution and preserved when factory setup fails; canonical and
2130
+ unadmitted queue images persist without truncation. Reload does not restart work.
2131
+ Switched-model context preflight no longer treats base64 transport as plain text
2132
+ but uses a rough image allowance alongside the conservative text guard. This is
2133
+ not exact provider token accounting or a promise that any image fits any model.
2134
+ Final actual-context model validation and all existing permission/budget rules apply.
2135
+
2136
+ SDK callers can pass `images=tuple[ImageContent, ...]` to `ChildSupervisor.start`
2137
+ or its steering/follow-up `control` methods. The application child APIs propagate
2138
+ these same typed inputs. No file URI, remote fetch or implicit text fallback is
2139
+ introduced. Claw requires the gateway's exact `child_images:1` capability and sends
2140
+ bytes through the existing checksummed chunk uploads. Large canonical image bodies
2141
+ are omitted from socket control receipts, explicitly marked `history_omitted`;
2142
+ use the separately owned child-source reader for complete **display** history,
2143
+ not raw binary/canonical data. Successful image refs are released; an exact replay
2144
+ of a cached request returns its old receipt without rerunning or requiring those refs.
2145
+
2146
+ Offline evidence includes both actual app/UI owners with file reads and 10 MiB
2147
+ payloads, the real Claw socket upload path, 2 MiB chunk uploads, queue settlement/
2148
+ reload, mismatched-receipt draft retention,
2149
+ and both private-tmux file/preview/review-cancel/terminal-recovery paths. Large test
2150
+ payloads exercise bounded byte transport with a valid PNG header, not a hosted
2151
+ pixel decoder or general model-provider interoperability.
2152
+
2153
+ Live queued-image return and stopped initial-task/input copies are retained only
2154
+ through the permissioned main-Agent/SDK path. Native queues are read-only; ordinary
2155
+ new child image submission and same-session transient child drafts remain separate.
2156
+ Memory caches are bounded and never automatically adopted by another owner;
2157
+ only primary drafts have the separate reviewed local snapshot flow. Child editor
2158
+ inputs remain same-session transient, not cross-process disk recovery. Native desktop
2159
+ clipboard/provider/decoder interoperability and uncommitted edits retain their
2160
+ existing limitations.
2161
+
2162
+
2163
+ ### Typed stopped-child image recovery through Agent/SDK
2164
+
2165
+ `recover_images` remains an explicit SDK/main-Agent queue operation with exact
2166
+ input `id` and queue `revision`. `ChildSupervisor.control` returns the verified
2167
+ non-destructive `image_recovery` payload and `queue.image_receipt`; the ordinary
2168
+ `agent_control` wrapper returns typed images plus receipt/count metadata. The
2169
+ text-only `recover` action refuses image-bearing inputs rather than dropping bytes.
2170
+ Running children use the separate owned live-return protocol, not stopped recovery.
2171
+
2172
+ The original record and its exact text/images/MIME types remain unchanged on copy.
2173
+ Owner/revision changes during byte preparation refuse delivery; cancellation waits
2174
+ for the actual owned decoder/hash worker. Image count, context and retained-byte
2175
+ limits remain enforced. No child Agent/model is constructed, no old approvals are
2176
+ restored and no queue input is automatically replayed.
2177
+
2178
+ There is no native **u** recovery action, stopped-image copy form or Claw
2179
+ `child_recovery_begin/chunk/end` UI transport. The native queue view receives only
2180
+ scoped metadata. Ordinary new child image submission, same-session transient child
2181
+ editor drafts and primary draft recovery keep their separate contracts.
2182
+
2183
+ ### Same-session transient child input recovery
2184
+
2185
+ **d** in the child roster or `/agents drafts` opens only the current session/
2186
+ context's unsent child inputs. Enter opens a complete text/settings/provenance/
2187
+ image-digest review, then a fresh physical Enter reopens the **same editing slot**.
2188
+ Current text/images, editing settings and cursor survive a view close/reopen;
2189
+ this is not a prior execution/approval receipt. Existing-child steering/follow-up
2190
+ reopens only while that exact child is running. No recovery submits work, changes
2191
+ the parent composer or bypasses the normal final task/access/tool review.
2192
+
2193
+ There is no cross-session catalog, duplicate-copy management, search, cache-delete,
2194
+ disk save/load/delete or child-autosave UI. The former **s**, **x**, **r**, **/**
2195
+ and **Delete** recovery-management keys are inert. `/agents saved` (including list/ID
2196
+ variants) refuses immediately without a disk job, command/socket request or background persistence. Existing
2197
+ `saved-child-drafts` files are neither inspected, migrated nor deleted.
2198
+
2199
+ The panel derives entries only from its exact current cache. Opening recovery in
2200
+ a new session/branch/connection context keeps only that current cache and drops
2201
+ old references rather than guessing/adopting another scope. A new application owner does not restore transient edits. Preview,
2202
+ focus/geometry changes, stale source identity and replaced/closed views cannot
2203
+ reuse old review proof. **p** opens the retained read-only image preview; returning
2204
+ requires fresh full review. Paste, repeat/release or unpainted Enter cannot confirm.
2205
+ Text/images stay within existing retention limits; closing a view does not invent
2206
+ durability or silently truncate data.
2207
+
2208
+ This removes only child editor disk/management controls. Actual Agent child input
2209
+ journals, initial-task records, stopped Agent/SDK `recover_images`/`recover_task` and durable
2210
+ returned-image backups remain separate explicit recovery paths described above.
2211
+ Primary `/draft save`/restore, primary autosave, disk receipts and quit safeguards
2212
+ remain separate and are described below.
2213
+
2214
+
2215
+ ### Explicit initial-task recovery after setup failure
2216
+
2217
+ A stopped child exposes a distinct `initial-task` row when setup failed before
2218
+ original task admission. Text and attachments remain available even with no child
2219
+ history. Pending/admitted/handled/uncertain/discarded state is recorded separately;
2220
+ a provider failure after admission does not relabel the task as unsent. Legacy or
2221
+ interrupted records without sufficient evidence are **uncertain**, not proof that
2222
+ no model/tool effects occurred.
2223
+
2224
+ The native queue is read-only and cannot copy/discard that row. The retained
2225
+ main-Agent/SDK queue actions `recover_task` and `remove_task` require its original
2226
+ ID/revision. Copy is non-destructive and returns typed image content when needed;
2227
+ discard commits the record before publishing removal and releases initial image
2228
+ bytes only after committed discard. Failed writes retain recovery, and cancellation
2229
+ waits for the actual writer. Neither operation restores approvals, restarts a child
2230
+ or rewrites canonical history. Ordinary edit/remove/return cannot reinterpret the
2231
+ initial-task row as live queued input.
2232
+
2233
+ Review old history and effects before explicitly starting any replacement task.
2234
+ No native task-recovery capability or binary copy transport is advertised; existing
2235
+ SDK journaling and same-session transient editor recovery are not removed.
2236
+
2237
+ ### Agent-tool-only live queued-image return
2238
+
2239
+ The native user interface offers neither manual live queue edit/reorder/remove/
2240
+ return nor stopped task/input copy controls. Those queue operations remain in the
2241
+ permissioned main-Agent/SDK backend; native queue inspection is read-only.
2242
+ The main Agent can use its ordinary permissioned `agent_control` tool with
2243
+ `action="queue"` and a JSON `text` request containing `return_prepare`,
2244
+ `return_commit` or `return_cancel` plus the required input/revision/receipt fields.
2245
+ Preparation returns typed image content and bounded token/receipt metadata; it
2246
+ never dequeues and does not embed raw base64 into model-visible prose.
2247
+
2248
+ The tool supplies its private nonserialized supervisor owner; models cannot pick
2249
+ one. Cancellation/abort/close revoke that owner. The existing token expiry,
2250
+ selection/revision/receipt checks and retained-byte limits remain. Durable removal
2251
+ and return-backup writes keep their existing owned settlement/no-automatic-replay
2252
+ rules. A generic SDK embedder still owns typed-history retention, persistence and
2253
+ ordinary tool permission hooks. A process-local token is not a promise of
2254
+ exactly-once side effects across crashes.
2255
+
2256
+ ### Concurrent return capacity and malformed queue transport
2257
+
2258
+ The four-slot live-return budget now includes **in-flight image preparations** as
2259
+ well as prepared leases/completed receipts. Slots are reserved before asynchronous
2260
+ validation yields and released on cancellation/failure. Simultaneous requests
2261
+ cannot each pass the limit and create unbounded image copies. This does not add
2262
+ crash durability or restore the removed native two-review return workflow.
2263
+ Preparation/commit ownership remains in the permissioned Agent tool/backend.
2264
+
2265
+ Claw's native queue boundary accepts only the exact list request. Retired mutation/
2266
+ recovery packets and malformed JSON fail without reaching backend mutation or byte
2267
+ preparation. The retained Agent/SDK queue validator still checks exact action fields;
2268
+ normal internal JSON-RPC and unrelated child controls are not removed.
2269
+
2270
+
2271
+ ### Image worker cancellation settlement
2272
+
2273
+ Image recovery/return preparation and sender decoding now wait for their actual
2274
+ owned worker thread to exit when cancelled. Cancellation revokes delivery: no
2275
+ receipt or binary frames are published afterward. Repeated cancellation does not
2276
+ release a preparation capacity slot while decoding/hashing is still running.
2277
+ Late worker errors are consumed during cancellation; ordinary results/errors are
2278
+ unchanged. Python cannot forcibly stop a thread, so cancellation settlement may
2279
+ outlast a transfer deadline while bounded local image work finishes. This is not
2280
+ process isolation, an OS sandbox or crash durability.
2281
+
2282
+
2283
+ ### POSIX child-record directory durability
2284
+
2285
+ Completed child-record writes now fsync the temporary file, atomically replace
2286
+ its destination, then fsync the containing directory. Newly created child storage
2287
+ directories use private modes and their parent directory entries are also flushed.
2288
+ Existing directory permissions are not changed. This applies to initial records,
2289
+ settled results and explicit recovery/discard metadata writes.
2290
+
2291
+ A directory-flush failure after replacement is an **uncertain committed outcome**:
2292
+ XDOG propagates the failure without rolling back or automatically rewriting. Inspect
2293
+ actual persisted state before retrying. Owned directory descriptors close even on
2294
+ failure. Non-POSIX platforms retain their existing behavior without an equivalent
2295
+ directory-fsync claim. These flush-order tests are not physical power-loss testing.
2296
+ Backend input journals and primary draft snapshots are separate layers,
2297
+ described below; flushing a child record does not persist a child editor.
2298
+
2299
+
2300
+ ### Write-ahead child input snapshots
2301
+
2302
+ Both clients now persist a bounded child steering/follow-up snapshot **before**
2303
+ acknowledging live queue acceptance. Text and images are stored in a private atomic
2304
+ `.inputs.json` sidecar using the child store's file/directory flush path. Failed
2305
+ writes refuse live admission. Cancellation waits for the actual admitted writer;
2306
+ terminal settlement waits too, so an old writer cannot overwrite a later settled
2307
+ record. No blocking filesystem writes are added to the agent event loop.
2308
+
2309
+ After an unclean restart, an interrupted child with a valid snapshot exposes those
2310
+ inputs as **crash-snapshot / uncertain** recovery rows. Recovery still requires an
2311
+ explicit permissioned Agent/SDK copy; the native view is metadata-only, and no Agent
2312
+ is constructed or restarted on load. Snapshots may contain inputs already consumed
2313
+ before the crash, and may precede subsequent edits/removals. Inspect history/workspace effects before any
2314
+ explicit resubmission. This is conservative data retention, NOT an exact once-only
2315
+ consumption journal or a claim that recovered inputs were never executed.
2316
+
2317
+ Settled child records take precedence over stale sidecars. The terminal record is
2318
+ flushed before journal cleanup, so a crash between those steps cannot revive old
2319
+ accepted inputs. An actual owned SIGKILL test verifies a previously acknowledged
2320
+ 2 MiB image input survives and is explicitly recoverable without agent creation;
2321
+ both native clients also verify their actual acceptance writes the sidecar.
2322
+ Backend journals do not persist child editor keystrokes; primary manual snapshots
2323
+ and optional primary autosave are separate. Physical-power-loss and
2324
+ uncertain admission/consumption boundaries retain their limits. No automatic
2325
+ replay or permission escalation is introduced.
2326
+
2327
+
2328
+ ### Write-ahead live queue changes
2329
+
2330
+ Agent/SDK live **edit**, **remove**, **move** and text-only **return** write their
2331
+ prospective queue snapshot before acknowledging the change. The runtime validates
2332
+ the input/revision and delivery lane first, writes off the agent loop, then checks
2333
+ the exact queue lease again before applying the live mutation. Failed writes leave
2334
+ the live queue and prior disk snapshot unchanged. Cancellation waits for the actual
2335
+ writer and does not falsely acknowledge a live change; terminal settlement replaces
2336
+ the prospective sidecar with actual final state.
2337
+
2338
+ An owned SIGKILL test acknowledges an image edit and a separate removal, kills the
2339
+ process, and verifies recovery retains the edited image but not the removed input.
2340
+ This covers acknowledged changes, not every ambiguous boundary: if the process dies
2341
+ after the prospective write but before live mutation/acknowledgment, the saved state
2342
+ is explicitly uncertain. Consumption during disk work rejects the stale mutation;
2343
+ there is no automatic replay. Agent-tool-owned image commits and settled
2344
+ input-consumption persistence are separate stages below, not native live-return UI.
2345
+ Primary draft snapshots do not remove ambiguous admission or physical-power-loss
2346
+ boundaries; child editor recovery remains transient.
2347
+
2348
+
2349
+ ### Write-ahead image-return commits
2350
+
2351
+ The retained backend's two-phase image-return commits persist the removal snapshot
2352
+ before acknowledgment. Exact owner/token/input/revision/byte-receipt validation
2353
+ runs before writing and again before actual live removal. Failed writes, cancelled
2354
+ writers, checkpoint selection or host revocation cannot remove the input through
2355
+ a stale commit. Writer cancellation waits for actual settlement. Exact completed
2356
+ commit retries return the original receipt without rewriting the journal.
2357
+
2358
+ An owned SIGKILL test acknowledges an image-return commit, kills the process, and
2359
+ verifies the returned input is absent from the restarted queue snapshot. This does
2360
+ not make native editor drafts durable; the backend's separate return backup is
2361
+ described below. A crash between a prospective disk write and live mutation/
2362
+ acknowledgment is still an uncertain boundary. The separate consumption hook below
2363
+ is not an atomic history-plus-queue transaction. Recovery never automatically
2364
+ replays work or restores old execution permissions.
2365
+
2366
+
2367
+ ### Durable returned-image handoff
2368
+
2369
+ Before a permissioned Agent-tool/SDK live image-return commit removes a queued
2370
+ input, the child backend persists an exact conservative text/image backup in the
2371
+ bounded `.returns.json` sidecar, then the prospective queue-removal snapshot.
2372
+ The same owner/token/input/revision/byte receipt is rechecked before actual removal.
2373
+ Failed or uncertain writes refuse removal or retain the conservative backup for
2374
+ settlement. Neither native client prepares or commits a live queue return.
2375
+
2376
+ After interruption, validated backups appear as `durable-return / uncertain`
2377
+ metadata. Terminal settlement writes them into the authoritative child record
2378
+ before sidecar cleanup. Native inspection cannot copy/discard them. Explicit
2379
+ main-Agent/SDK `recover_images` returns a non-destructive exact typed copy, while
2380
+ `remove` is a separate revision-checked durable discard. A backup may exist even if
2381
+ removal failed; previous effects are not undone. Inspect history/workspace before
2382
+ explicit resubmission. Startup never reinserts backups into a live queue.
2383
+
2384
+ Existing bounds remain 32 backup rows / 40 MiB images, separate from pending-input
2385
+ retention. Capacity exhaustion refuses new commits rather than dropping bytes.
2386
+ The main-Agent wrapper emits typed images and bounded receipts; an SDK embedder
2387
+ owns retention and adoption. Native child edits remain same-session transient;
2388
+ this backend durability is not a child disk-save UI or an exactly-once/power-loss
2389
+ guarantee.
2390
+
2391
+ ### Return retry after partial write failure
2392
+
2393
+ An explicit same-lease image-return retry now reuses an identical retained backup
2394
+ instead of adding a duplicate recovery row. This covers a failure after backup
2395
+ replacement or during the following queue journal write. Conflicting backup identity/
2396
+ content still refuses; a completed retry does not rewrite or remove twice. This is
2397
+ not automatic retry permission: inspect uncertain effects/receipts before retrying.
2398
+
2399
+
2400
+ ### Awaited child input-consumption persistence
2401
+
2402
+ Identified child inputs now trigger an awaited host persistence hook after history
2403
+ admission or explicit extension handling, before the next model request. The child
2404
+ host writes its current remaining queue off the agent loop and settles the actual
2405
+ writer on cancellation. A failed write stops continuation; already admitted history
2406
+ or handler effects are not rolled back. Other generic Agent clients have no hook
2407
+ unless explicitly configured with `input_settled` / `set_input_settled`.
2408
+
2409
+ An owned SIGKILL test reaches the next model boundary, verifies the consumed input
2410
+ has been flushed out of the queue snapshot, kills the process, and confirms it is
2411
+ not offered as queued recovery data. A crash between admission and flush remains
2412
+ uncertain; this is not an atomic history-plus-queue transaction or exact-once effect
2413
+ guarantee. Primary manual snapshots and opted-in primary autosave do not promise
2414
+ that in-flight edits survive or prove physical-power-loss/native-filesystem
2415
+ conformance; host/platform interoperability retains its own limits.
2416
+
2417
+
2418
+ ### Retained primary snapshot storage and quit settlement
2419
+
2420
+ The shared snapshot codec/store/I/O/autosave primitives remain for primary drafts.
2421
+ Private no-follow ownership/mode checks, atomic publication, fsync, create-only
2422
+ manual saves, exact-owner autosave updates and conservative recovery are unchanged.
2423
+ A queued receipt remains owned until its worker exits; the terminal never joins a
2424
+ live disk worker. Lock contention has a bounded three-second acquisition deadline,
2425
+ not a promise about arbitrary filesystem stalls. Storage failures retain editable
2426
+ source, redact diagnostics and do not automatically retry uncertain effects.
2427
+
2428
+ Graceful quit waits for admitted **primary** writes and pending opted-in primary
2429
+ autosave. Argument completion, basic dialogs, native rendering/input and Claw's
2430
+ owned name read remain usable until exit is admitted. A new storage failure cancels
2431
+ deferred quit. Repeated exit requests do not duplicate teardown. Transient child
2432
+ edits create no disk/background job or fictitious receipt barrier; no files are
2433
+ deleted when their current-context cache references are released.
2434
+
2435
+
2436
+ ### Primary draft save and explicit recovery
2437
+
2438
+ Press **Ctrl+Alt+S** while the primary composer is focused to review a private,
2439
+ create-only snapshot without consuming its text or attachments. `/draft save`
2440
+ opens the same exact-composer review; submitting a slash command normally consumes
2441
+ that command's editor text, so prefer the shortcut for an existing typed prompt.
2442
+ No autosave opt-in is required. The `save_draft` action is configurable in
2443
+ `keybindings.json`: `{"save_draft":"f8"}` remaps it and `{"save_draft":[]}` disables
2444
+ it without a hard-coded fallback. `/keys` shows the current binding.
2445
+
2446
+ Save and recovery use a **standalone primary-draft surface**, never the child
2447
+ browser. `/draft restore [SNAPSHOT_ID]` opens an explicit selector of at most **32**
2448
+ snapshots or loads one exact ID. `/draft saved [SNAPSHOT_ID]` remains an alias;
2449
+ `/draft saved list` opens the same bounded selector, not a management catalog.
2450
+ Each entry discloses its ID and stored action/slot, scope and label; Enter opens
2451
+ full text/provenance/image-digest review before any restore can be confirmed.
2452
+ There is no primary catalog/delete/search management UI or automatic latest-slot
2453
+ selection, pruning or migration. A full store reports an explicit error and keeps
2454
+ the unsaved composer and existing snapshots unchanged.
2455
+
2456
+ Coding uses its session-manager directory's `saved-parent-drafts`; Claw uses its
2457
+ local data directory's `saved-parent-drafts`. These existing stores can contain
2458
+ multiple recorded scopes. Stored context strings are provenance, not a durable
2459
+ workspace/group identity or an instruction to select a snapshot. IDs are not
2460
+ timestamps; recovery never infers a latest snapshot from ID order or file mtime,
2461
+ guesses another scope, or silently moves/deletes existing records.
2462
+
2463
+ Restoration copies **text/images only** into an unchanged **empty** composer.
2464
+ Text, attachments, cursor, context and view ownership are checked against the
2465
+ captured admission state; a nonempty or changed composer is preserved. Old
2466
+ model/tools/access/configuration are not adopted, and the stored cursor is not
2467
+ restored: native `set_text` places the editing cursor at the end. Nothing submits
2468
+ a prompt, invokes a model or changes history/permissions. Primary text supports
2469
+ 64 KiB; snapshots permit four images, 10 MiB each / 40 MiB total. Existing validated
2470
+ image and combined retained-byte limits remain, with no truncation or partial
2471
+ recovery. Saved snapshots remain after submit/clear; this UI never deletes them.
2472
+
2473
+ ### Optional primary autosave
2474
+
2475
+ `/draft autosave on` enables session-local primary-composer snapshots. It is **OFF
2476
+ by default**, resets on restart and discloses PRIVATE PLAINTEXT local storage.
2477
+ `off` stops future scheduling, not an already admitted write. After the existing
2478
+ 0.5-second debounce, exact-owner updates use only that owner's prior ID/digest;
2479
+ manual saves stay create-only and externally changed snapshots are not overwritten.
2480
+ A changed context creates a separate snapshot rather than adopting another owner's
2481
+ update receipt. Failure stops autosave until explicit re-enable, with no automatic
2482
+ retry of uncertain effects. Child drafts are not included; child autosave is removed.
2483
+
2484
+ Completed autosaves retain only their ID/digest receipt, not another decoded
2485
+ image/text copy outside retention accounting. Native status distinguishes pending,
2486
+ writing, committed and uncertain. Committed means a **polled disk receipt**, not
2487
+ per-keystroke or physical-power-loss durability. Debounce and in-flight crash
2488
+ windows remain; recovery after restart always requires explicit selection/review.
2489
+
2490
+ ### Primary review, preview and quit ownership
2491
+
2492
+ Every task/provenance/image page must be painted at the current review width before
2493
+ a fresh physical Enter can admit save/restore. Paste, repeat/release and unpainted
2494
+ Enter cannot confirm. **p** previews images; **Left/Right** selects an attachment
2495
+ and **Escape** returns to review. Preview performs no draft action and returning
2496
+ requires fresh full review. Narrow/zero-budget or changed geometry/focus cannot
2497
+ reuse earlier consent. Native USER input, shortcuts and approval safety remain.
2498
+
2499
+ Reads and confirmations bind the exact primary surface, context and composer.
2500
+ Closing/replacing it or a focus/owner change revokes late delivery and old callbacks;
2501
+ returning focus does not revive a former actor. Extension questions, output reviews,
2502
+ native overlays and Coding approval prompts/waiters retain input priority. A delayed
2503
+ read cannot reopen a dismissed view or steal modal focus. Escape/cancel releases
2504
+ transient preview/review images without deleting files or abandoning admitted I/O.
2505
+ All unrelated composer/queue/editable-image owners remain counted.
2506
+
2507
+ Graceful quit waits for admitted primary disk operations and flushes pending
2508
+ opted-in primary autosave. Child editor recovery creates no disk operation.
2509
+ Input services stay live while waiting; primary edits during the wait are flushed
2510
+ when autosave is enabled. A new storage
2511
+ failure cancels deferred quit and leaves the UI open for inspection. Single-use save
2512
+ admission, redacted generic errors, private-path/fsync protections and no automatic
2513
+ replay remain. These are bounded local snapshot/recovery guarantees, not proof of
2514
+ every filesystem/power-loss behavior. Remote parent-draft control is removed; no
2515
+ Coding frontend RPC or Claw gateway draft negotiation is used.
2516
+
2517
+
2518
+ ### Read-only image preview in child draft reviews
2519
+
2520
+ Press **p** in current-session child recovery or its full review to preview images
2521
+ before a separate reviewed current-session reopen. **Left/Right** chooses attachments;
2522
+ **Escape** returns to review, with fresh full painting required before confirmation.
2523
+ Preview performs no draft action, file deletion or agent call. Changed sources
2524
+ invalidate preview/review rather than applying an action against stale bytes.
2525
+
2526
+ ### Literal argument suffix, quotes and escapes (UI-035)
2527
+
2528
+ Registered completions replace the **entire cursor-local token**, including its
2529
+ suffix. The callback receives the literal prefix and (when independently
2530
+ negotiated) copied `argument_context` codepoint coordinates. It can inspect the
2531
+ suffix as `arguments[cursor:end]` and must return the complete literal replacement
2532
+ in `value`, including any intended quotes/escapes. No automatic quoting, shell
2533
+ expansion, suffix concatenation, command execution or prompt submission occurs.
2534
+
2535
+ Outside single quotes, a backslash protects the next character, including a
2536
+ space or quote; an escaped backslash does not protect the following separator.
2537
+ Inside single quotes backslashes remain literal. An unfinished quote extends the
2538
+ token to the end of the line. Between arguments, completion can insert into an
2539
+ empty cursor-local whitespace slot without consuming the next argument. Tab/Enter
2540
+ inserts only; undo restores the original token and surrounding arguments. Existing
2541
+ registration/owner/draft/cursor/cancellation fences still apply. Actual Coding and
2542
+ Claw worker/socket checks and Linux private-terminal suffix/quote/escape/undo and
2543
+ worker-cancellation recovery have passed; no non-Linux native validation is claimed.
2544
+
2545
+ ## Supported Coding entry modes
2546
+
2547
+ Coding supports the native interactive TUI and non-interactive print mode. The
2548
+ former `--rpc` JSON-lines frontend mode and its public `run_agent(rpc=...)` argument
2549
+ are removed, including remote draft, history/image, progress, editor/session/host,
2550
+ and custom-UI protocols. These removals do not remove internal Agent events, local
2551
+ history/export/persistence, native drafts, or the ACP/session controller and durable
2552
+ automatic inbox described below. Unknown `--rpc` input is rejected before startup.
2553
+ Private extension-worker RPC, MCP JSON-RPC and ACP remain separate retained
2554
+ transports; removing the frontend mode does not remove those protocols.
2555
+
2556
+ ## ACP session routing, automatic inbox and batched turns
2557
+
2558
+ `--session ID --prompt TEXT` sends through ACP to the exact live owner without
2559
+ constructing another Agent. It differs from `--resume-id ID` (explicit history
2560
+ restore), rejects inactive/unknown/cwd mismatch, and cannot override target policy.
2561
+ `--acp` is the standard stdio adapter; `--acp --session ID` fixes a bridge to an
2562
+ existing owner. Ordinary native/print/navigation usage does not require optional ACP
2563
+ activation; the pinned SDK currently supports Python 3.12–3.14 only.
2564
+
2565
+ Callbacks use an explicitly configured **ACP endpoint + session**, not a required
2566
+ coding CLI subprocess or TUI event host. The independent lightweight ingress
2567
+ (`python -m xdog.coding.acp.ingress_main --help`) receives into a durable per-session
2568
+ inbox even when every TUI/owner is closed. It does not create an Agent or silently
2569
+ restore history. Starting/stopping the ingress is explicit and independent.
2570
+
2571
+ `/inbox list [OFFSET]` and `/inbox show ID` inspect without scheduling work.
2572
+ Every external ACP prompt/callback first enters the same durable Inbox. An
2573
+ activated owner automatically consumes pending messages, whether they arrived
2574
+ online or while all owners were offline. There is no message-approval dialog,
2575
+ human wake-up budget, or approval-bearing ACP resume extension. `/inbox cancel ID`
2576
+ targets pending intake; `/inbox retry ID` explicitly retries interrupted work while
2577
+ retaining its old attempt facts. Actual tool calls still use the existing policy:
2578
+ read-only calls may run automatically, restricted calls need approval, and no
2579
+ approver means fail-closed unless the user explicitly selected `allow-all`.
2580
+
2581
+ `max_messages_per_turn` defaults to **10**, accepts only integer **1..128** (not
2582
+ booleans), and follows explicit SDK override > saved session > project > global >
2583
+ default precedence. Five inputs remain five independent history messages, with
2584
+ separate IDs/sources/typed attachments, but one shared Agent turn and response/tool
2585
+ stream. Setting 1 restores single-input selection. Selection is fixed; later
2586
+ arrivals wait for the next turn, and byte/context/image limits can narrow a batch
2587
+ without dropping messages. TUI live/replay shows shared output once.
2588
+
2589
+ A shared batch cannot withdraw an already admitted message from model context:
2590
+ cancel/disconnect ends that peer's waiter, not the other members' execution.
2591
+ Running crashes become interrupted and are not replayed automatically. SDK/print/ACP
2592
+ report finalization or persistence failures as errors, not blank success.
2593
+
2594
+ Optional `--session ID --enqueue --message-id STABLE_ID --prompt TEXT` writes data
2595
+ without ACP/model startup, with a durable JSON receipt, not an execution result.
2596
+ It cannot combine with model/permission/resume overrides. Enqueue ACK loss permits
2597
+ same-ID/content dedup retry; standard prompt outcome-unknown never does. There is
2598
+ no automatic harness/observer startup or exactly-once side-effect guarantee.
2599
+
2600
+ The old event-host package/environment/capabilities are removed, while stored
2601
+ `xdog.external_event.v1` history remains readable. New external model input is
2602
+ `xdog.session_input.v1`; a nonsecret `XDOG_SESSION_ID` tool-environment hint follows
2603
+ session navigation without granting permissions. See the [full protocol and
2604
+ receiver setup](../../docs/acp-session-routing.md).
2605
+
2606
+ ### Explicit MCP arguments
2607
+
2608
+ After explicitly connecting a server, prompt arguments are entered as a JSON
2609
+ object and resource reads use an explicitly supplied resolved URI. Submitted
2610
+ input stays editable after errors or cancellation. Catalog reads, multitype
2611
+ previews, insert/export and existing permission boundaries remain; manual named
2612
+ argument/opaque-resource completion pickers are removed. This does not remove
2613
+ the lower-level MCP completion client API or extension command argument completion.
2614
+
2615
+
2616
+ ### Basic extension interaction scope
2617
+
2618
+ Trusted extensions can use `api.input`, `api.confirm` and `api.select` with normal
2619
+ cancellation, plus bounded notifications and simple text status. Arbitrary custom
2620
+ renderers, typed plugin forms, nested dialogs, extension overlays/fullscreen frames
2621
+ and widget layouts are removed. Native approval and recovery reviews remain host-
2622
+ owned; they expose no plugin layout or editor/session-mutation authority. Core TUI
2623
+ overlays, transcript fullscreen, Unicode, clipping, cursor and tool-approval behavior
2624
+ remain.