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