taskuary 0.3.9.2__tar.gz → 0.3.9.4__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 (753) hide show
  1. {taskuary-0.3.9.2/taskuary.egg-info → taskuary-0.3.9.4}/PKG-INFO +3 -5
  2. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/README.md +2 -4
  3. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/pyproject.toml +1 -1
  4. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/advisor.py +193 -42
  5. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/agents.py +12 -5
  6. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/aisetup.py +4 -4
  7. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/alchemy.py +2 -1
  8. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/asks.py +1 -1
  9. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/assistant.py +19 -14
  10. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/batch.py +131 -5
  11. taskuary-0.3.9.4/taskuary/buttons.json +52 -0
  12. taskuary-0.3.9.4/taskuary/buttons.py +42 -0
  13. taskuary-0.3.9.4/taskuary/capabilities.py +82 -0
  14. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/channels.py +8 -6
  15. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chatgptauth.py +15 -3
  16. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ci.py +4 -2
  17. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cli.py +3 -2
  18. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/compose.py +83 -31
  19. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/concierge.py +244 -181
  20. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/connectorcatalog.json +12 -0
  21. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/counsel.py +20 -1
  22. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/db.py +3 -1
  23. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/demo.py +134 -45
  24. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/evalset.py +3 -2
  25. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/firstrun.py +201 -37
  26. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/funnel.py +72 -107
  27. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/funnel_presentation.py +109 -1
  28. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/funnel_selection.py +1 -1
  29. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/general.py +13 -6
  30. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/guard.py +1 -0
  31. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/handbook.py +5 -3
  32. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/histgen.py +3 -1
  33. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/images.py +2 -1
  34. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/imapmail.py +3 -2
  35. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ingest.py +42 -12
  36. taskuary-0.3.9.4/taskuary/lanes.json +278 -0
  37. taskuary-0.3.9.4/taskuary/lanes.py +97 -0
  38. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/llm.py +7 -1
  39. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/lookups.py +5 -4
  40. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/markets.py +6 -3
  41. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/messengers.py +2 -2
  42. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/operations.py +4 -1
  43. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/outbound.py +34 -11
  44. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/outbox.py +5 -5
  45. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/outcomes.py +1 -1
  46. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_unread.py +6 -5
  47. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/proposals.py +27 -42
  48. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/remind.py +3 -2
  49. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/remote_assistant.py +52 -71
  50. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/reports.py +61 -24
  51. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/research.py +12 -8
  52. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/responder.py +45 -5
  53. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/scopes.py +2 -1
  54. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/selfclose.py +6 -0
  55. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/server.py +86 -48
  56. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/settings_defaults.json +1 -0
  57. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/settings_schema.json +29 -23
  58. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/setup.py +40 -26
  59. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/since.py +6 -2
  60. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/slots.py +17 -22
  61. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/store.py +22 -3
  62. taskuary-0.3.9.4/taskuary/templates/counsel.md +108 -0
  63. taskuary-0.3.9.4/taskuary/templates/history/counsel-0.3.9.3-audit.md +108 -0
  64. taskuary-0.3.9.4/taskuary/templates/history/counsel-0.3.9.3-buttons.md +108 -0
  65. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/terminal.py +24 -8
  66. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/toolcatalog.py +37 -15
  67. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/triage.py +13 -4
  68. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/verdicts.py +23 -46
  69. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/voice.py +3 -2
  70. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/walk.py +10 -10
  71. taskuary-0.3.9.4/taskuary/web/assets/AssistantGame-CcG9vjWw.js +4 -0
  72. taskuary-0.3.9.2/taskuary/web/assets/GameScene-CD364KhR.js → taskuary-0.3.9.4/taskuary/web/assets/GameScene-xQkkdnyo.js +1 -1
  73. taskuary-0.3.9.4/taskuary/web/assets/HubView-B6GquZ4c.js +1 -0
  74. taskuary-0.3.9.4/taskuary/web/assets/TasksView-D4p3JiDN.js +1 -0
  75. taskuary-0.3.9.4/taskuary/web/assets/index-5REVSOmO.js +666 -0
  76. taskuary-0.3.9.2/taskuary/web/assets/index-dSnQFS_I.css → taskuary-0.3.9.4/taskuary/web/assets/index-CK_5N4BE.css +1 -1
  77. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/index.html +2 -2
  78. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/welcome.py +11 -7
  79. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/witness.py +19 -4
  80. taskuary-0.3.9.4/taskuary/words.json +31 -0
  81. taskuary-0.3.9.4/taskuary/words.py +36 -0
  82. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/workerstate.py +5 -0
  83. taskuary-0.3.9.4/taskuary/workflows.py +309 -0
  84. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/wrapup.py +102 -18
  85. {taskuary-0.3.9.2 → taskuary-0.3.9.4/taskuary.egg-info}/PKG-INFO +3 -5
  86. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/SOURCES.txt +29 -6
  87. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_advisor.py +83 -7
  88. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_reply.py +15 -0
  89. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_alchemy.py +2 -1
  90. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_answered_yourself.py +1 -1
  91. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_answers.py +12 -12
  92. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_api.py +20 -6
  93. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_appfacts.py +1 -1
  94. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant.py +1 -1
  95. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_acts.py +1 -1
  96. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_reactions.py +23 -19
  97. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_auto_start.py +9 -8
  98. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_batch.py +1 -1
  99. taskuary-0.3.9.4/tests/test_batch_session_end.py +386 -0
  100. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_resolver.py +4 -3
  101. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_said.py +1 -1
  102. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_browser_workflow.py +1 -1
  103. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_button_promises.py +2 -2
  104. taskuary-0.3.9.4/tests/test_buttons.py +224 -0
  105. taskuary-0.3.9.4/tests/test_capabilities.py +133 -0
  106. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_proposals.py +58 -9
  107. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_setup.py +8 -4
  108. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chatformat.py +1 -1
  109. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_connections.py +3 -3
  110. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_close_slots.py +11 -11
  111. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_closeout.py +17 -17
  112. taskuary-0.3.9.4/tests/test_coding_needs_a_cli.py +68 -0
  113. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_compose.py +3 -3
  114. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_compose_sources.py +2 -2
  115. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_compose_workflows.py +16 -2
  116. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_concierge.py +96 -13
  117. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_continue_session.py +4 -4
  118. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_core.py +9 -4
  119. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_demo.py +105 -2
  120. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ending_a_run_writes_the_answer.py +1 -1
  121. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_explicit_completion.py +2 -1
  122. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_firstrun.py +114 -10
  123. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_funnel.py +1 -1
  124. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general.py +3 -3
  125. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general_report_note.py +1 -1
  126. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_chat.py +2 -2
  127. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handbook.py +7 -1
  128. taskuary-0.3.9.4/tests/test_hipaa_ai.py +76 -0
  129. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ideas_triage.py +8 -4
  130. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ignore_sender.py +1 -1
  131. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lane_vocabulary.py +2 -1
  132. taskuary-0.3.9.4/tests/test_lanes_registry.py +71 -0
  133. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_later_today.py +9 -0
  134. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lifecycle.py +16 -8
  135. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_no_reply_is_the_writers_call.py +1 -1
  136. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_onboarding_walk.py +4 -2
  137. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_openai_compatible_brains.py +3 -2
  138. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_outbound_reports.py +2 -2
  139. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_browse_pass.py +1 -1
  140. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_picks.py +5 -5
  141. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_walk_ux.py +10 -5
  142. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbook_and_closeout.py +10 -10
  143. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_remind.py +4 -4
  144. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_remote_assistant.py +2 -2
  145. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reopened_conversation.py +1 -1
  146. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_channels.py +1 -1
  147. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_watch.py +4 -3
  148. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_order_and_research.py +1 -1
  149. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_routing.py +5 -4
  150. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_triage.py +9 -6
  151. taskuary-0.3.9.4/tests/test_report_triage_line.py +270 -0
  152. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_review_delivery_safety.py +5 -5
  153. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_roles.py +4 -4
  154. taskuary-0.3.9.4/tests/test_row_presentation.py +84 -0
  155. taskuary-0.3.9.4/tests/test_send_is_not_close.py +131 -0
  156. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_send_outcomes.py +6 -6
  157. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_endings.py +2 -2
  158. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_settings_paths.py +14 -5
  159. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_settings_schema.py +2 -2
  160. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup.py +26 -17
  161. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup_about.py +11 -1
  162. taskuary-0.3.9.4/tests/test_setup_state.py +121 -0
  163. taskuary-0.3.9.4/tests/test_signature_learn.py +57 -0
  164. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_since.py +12 -1
  165. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_skillimport.py +1 -1
  166. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_email.py +3 -3
  167. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_taskstate.py +7 -5
  168. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_terminal.py +3 -2
  169. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_thinking_model_room.py +2 -2
  170. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_joins.py +3 -1
  171. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_urgent.py +1 -1
  172. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_voice.py +5 -4
  173. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_welcome_and_voice.py +8 -2
  174. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_why_not_started.py +6 -6
  175. taskuary-0.3.9.4/tests/test_words.py +72 -0
  176. taskuary-0.3.9.4/tests/test_workflow_brain.py +196 -0
  177. taskuary-0.3.9.4/tests/test_workflow_one_road.py +200 -0
  178. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_workflows.py +12 -7
  179. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_chipverbs.py +1 -1
  180. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_toolcatalog.py +8 -8
  181. taskuary-0.3.9.2/taskuary/lanes.json +0 -208
  182. taskuary-0.3.9.2/taskuary/web/assets/AssistantGame-BfHjsQy0.js +0 -4
  183. taskuary-0.3.9.2/taskuary/web/assets/HubView-BBhAZ5Hj.js +0 -1
  184. taskuary-0.3.9.2/taskuary/web/assets/TasksView-CoJa2HrT.js +0 -1
  185. taskuary-0.3.9.2/taskuary/web/assets/index-D0DogMv8.js +0 -658
  186. taskuary-0.3.9.2/taskuary/workflows.py +0 -151
  187. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/LICENSE +0 -0
  188. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/setup.cfg +0 -0
  189. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/__init__.py +0 -0
  190. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/acp.py +0 -0
  191. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/aidefaults.py +0 -0
  192. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/appfacts.py +0 -0
  193. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/artifacts.py +0 -0
  194. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/assistantblocks.py +0 -0
  195. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/autoreply.py +0 -0
  196. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/aws.py +0 -0
  197. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/azure.py +0 -0
  198. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/background.py +0 -0
  199. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/blackboard.py +0 -0
  200. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/brief.py +0 -0
  201. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/browserview.py +0 -0
  202. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/bugreport.py +0 -0
  203. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/calendar.py +0 -0
  204. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/categories.py +0 -0
  205. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chains.py +0 -0
  206. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chatformat.py +0 -0
  207. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/chatservers.py +0 -0
  208. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/claude_artifacts.py +0 -0
  209. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cli_connections.py +0 -0
  210. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cli_install_terminal.py +0 -0
  211. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cliinstall.py +0 -0
  212. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/climodels.py +0 -0
  213. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/clipool.py +0 -0
  214. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/clis.py +0 -0
  215. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/clisetup.py +0 -0
  216. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/cloudfix.py +0 -0
  217. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/config.py +0 -0
  218. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/connectorcatalog.py +0 -0
  219. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/context.py +0 -0
  220. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/continuity.py +0 -0
  221. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/databases.py +0 -0
  222. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/deps.py +0 -0
  223. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/desktop.py +0 -0
  224. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/devtools.py +0 -0
  225. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/digest.py +0 -0
  226. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/docsync.py +0 -0
  227. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/doorway_browse.py +0 -0
  228. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/evening.py +0 -0
  229. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/files.py +0 -0
  230. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/floor.py +0 -0
  231. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ghcloseout.py +0 -0
  232. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/github.py +0 -0
  233. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/goals.py +0 -0
  234. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/handraise.py +0 -0
  235. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/hooks.py +0 -0
  236. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/hub.py +0 -0
  237. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/imessage.py +0 -0
  238. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/instance.py +0 -0
  239. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/intacct.py +0 -0
  240. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/interview.py +0 -0
  241. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/invoice_workflow.py +0 -0
  242. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/jev.py +0 -0
  243. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/kbembed.py +0 -0
  244. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/knowledge.py +0 -0
  245. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/launchkey.py +0 -0
  246. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/learn.py +0 -0
  247. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/learnedgraph.py +0 -0
  248. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/linkedin.py +0 -0
  249. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/live.py +0 -0
  250. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/logs.py +0 -0
  251. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/mailauth.py +0 -0
  252. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/mcp.py +0 -0
  253. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/msauth.py +0 -0
  254. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/mssql.py +0 -0
  255. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/net.py +0 -0
  256. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/origin.py +0 -0
  257. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/ownwork.py +0 -0
  258. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/people.py +0 -0
  259. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/people_pages.py +0 -0
  260. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/playbook_facts.py +0 -0
  261. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/playbooks.py +0 -0
  262. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/pm.py +0 -0
  263. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/policy.py +0 -0
  264. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/problems.py +0 -0
  265. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing.py +0 -0
  266. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_all.py +0 -0
  267. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_inventory.py +0 -0
  268. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_membership.py +0 -0
  269. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_navigation.py +0 -0
  270. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_order.py +0 -0
  271. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_projection.py +0 -0
  272. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_rail.py +0 -0
  273. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_reads.py +0 -0
  274. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/processing_startup.py +0 -0
  275. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/projects.py +0 -0
  276. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/promptmap.py +0 -0
  277. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/proof.py +0 -0
  278. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/quickbooks.py +0 -0
  279. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/rank.py +0 -0
  280. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/redact.py +0 -0
  281. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/reshape.py +0 -0
  282. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/retention.py +0 -0
  283. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/robinhood.py +0 -0
  284. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/roles.py +0 -0
  285. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/routing.py +0 -0
  286. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/routingmemory.py +0 -0
  287. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/search.py +0 -0
  288. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/semantic.py +0 -0
  289. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/senders.py +0 -0
  290. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sentjudge.py +0 -0
  291. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/session_artifacts.py +0 -0
  292. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sessionfiles.py +0 -0
  293. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sessionrecord.py +0 -0
  294. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/settings_schema.py +0 -0
  295. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sharepoint.py +0 -0
  296. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/sheets.py +0 -0
  297. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/simplefin.py +0 -0
  298. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/skillimport.py +0 -0
  299. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/skills/soul-interview/SKILL.md +0 -0
  300. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/skills/taskuary-setup/SKILL.md +0 -0
  301. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/social.py +0 -0
  302. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/spawn.py +0 -0
  303. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/taskstate.py +0 -0
  304. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/teller.py +0 -0
  305. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/agent.md +0 -0
  306. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/analyst.md +0 -0
  307. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/ap.md +0 -0
  308. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/assistant.md +0 -0
  309. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/coding.md +0 -0
  310. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/coordinator.md +0 -0
  311. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/digest.md +0 -0
  312. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.3.5.md +0 -0
  313. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.8.md +0 -0
  314. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.9-examples.md +0 -0
  315. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.9-remind.md +0 -0
  316. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.6.9.md +0 -0
  317. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.7.10.md +0 -0
  318. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.7.4.md +0 -0
  319. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/history/counsel-0.3.7.7.md +0 -0
  320. /taskuary-0.3.9.2/taskuary/templates/counsel.md → /taskuary-0.3.9.4/taskuary/templates/history/counsel-0.3.9.3.md +0 -0
  321. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/how-it-works.md +0 -0
  322. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/job.md +0 -0
  323. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/learned.md +0 -0
  324. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/marketer.md +0 -0
  325. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/playbook.md +0 -0
  326. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/profile.md +0 -0
  327. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/researcher.md +0 -0
  328. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/soul.md +0 -0
  329. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/style.md +0 -0
  330. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/trader.md +0 -0
  331. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/templates/triage.md +0 -0
  332. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/testing.py +0 -0
  333. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/toil.py +0 -0
  334. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/treg.py +0 -0
  335. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/triage_kind_rules.json +0 -0
  336. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/update.py +0 -0
  337. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/vault.py +0 -0
  338. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/wabridge.py +0 -0
  339. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/waitroom.py +0 -0
  340. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/favicon.ico +0 -0
  341. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/favicon.png +0 -0
  342. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/assistant.png +0 -0
  343. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/board.png +0 -0
  344. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/connections.png +0 -0
  345. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/docs.png +0 -0
  346. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/hub.png +0 -0
  347. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/reports.png +0 -0
  348. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/settings.png +0 -0
  349. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/web/walk/tasks.png +0 -0
  350. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/webguard.py +0 -0
  351. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/bridge.mjs +0 -0
  352. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/package.json +0 -0
  353. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/policy.mjs +0 -0
  354. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/poll.mjs +0 -0
  355. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whatsapp/roster.mjs +0 -0
  356. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/whoami.py +0 -0
  357. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary/zoho.py +0 -0
  358. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/dependency_links.txt +0 -0
  359. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/entry_points.txt +0 -0
  360. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/requires.txt +0 -0
  361. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/taskuary.egg-info/top_level.txt +0 -0
  362. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_acp.py +0 -0
  363. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_advisor_idea_words.py +0 -0
  364. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_answer_route.py +0 -0
  365. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_answers_and_reminders.py +0 -0
  366. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_asking.py +0 -0
  367. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_environment.py +0 -0
  368. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_identity.py +0 -0
  369. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_profiles.py +0 -0
  370. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_sentence.py +0 -0
  371. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_source.py +0 -0
  372. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_agent_wall.py +0 -0
  373. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ai_defaults.py +0 -0
  374. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ai_not_overruled.py +0 -0
  375. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_aisetup.py +0 -0
  376. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_an_inbox_is_not_a_destination.py +0 -0
  377. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_api_web.py +0 -0
  378. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_api_worker_signals.py +0 -0
  379. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_app_uptime.py +0 -0
  380. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_approval_interrupt.py +0 -0
  381. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_approve_what_was_shown.py +0 -0
  382. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_archive_is_read.py +0 -0
  383. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_asks.py +0 -0
  384. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_blocks.py +0 -0
  385. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_can_look_things_up.py +0 -0
  386. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_doorways.py +0 -0
  387. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_fast.py +0 -0
  388. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_ideas.py +0 -0
  389. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_notifications.py +0 -0
  390. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_presentation.py +0 -0
  391. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_assistant_verdicts.py +0 -0
  392. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_async_triage.py +0 -0
  393. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_audit_chain.py +0 -0
  394. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_audit_fixes.py +0 -0
  395. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_autoreply.py +0 -0
  396. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_aws_region.py +0 -0
  397. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_azure_discovery.py +0 -0
  398. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_background_work.py +0 -0
  399. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_banner_is_one_rule.py +0 -0
  400. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_blackboard.py +0 -0
  401. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_layer.py +0 -0
  402. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_brain_reaches_the_session.py +0 -0
  403. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_browser_session.py +0 -0
  404. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_browserview.py +0 -0
  405. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport.py +0 -0
  406. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport_api.py +0 -0
  407. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport_draft.py +0 -0
  408. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_bugreport_scrub.py +0 -0
  409. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_calendar.py +0 -0
  410. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_calendar_today.py +0 -0
  411. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_canvas_relay.py +0 -0
  412. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_canvas_sections.py +0 -0
  413. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_card_story_phone.py +0 -0
  414. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_categories.py +0 -0
  415. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cc.py +0 -0
  416. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cc_triage.py +0 -0
  417. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_doors.py +0 -0
  418. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_echo_mail.py +0 -0
  419. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_freshness.py +0 -0
  420. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_is_not_one_task.py +0 -0
  421. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_queue.py +0 -0
  422. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_relationship.py +0 -0
  423. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_retention.py +0 -0
  424. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_shows.py +0 -0
  425. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chat_trust.py +0 -0
  426. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chatgptauth.py +0 -0
  427. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chatservers.py +0 -0
  428. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_chinese_clis.py +0 -0
  429. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_claude_artifacts.py +0 -0
  430. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_clean_context.py +0 -0
  431. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_failure.py +0 -0
  432. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_help.py +0 -0
  433. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_install.py +0 -0
  434. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_install_terminal.py +0 -0
  435. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_not_assumed.py +0 -0
  436. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_on_fresh_path.py +0 -0
  437. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_prompt_road.py +0 -0
  438. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_setup.py +0 -0
  439. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cli_update.py +0 -0
  440. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_climodels.py +0 -0
  441. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_clipool.py +0 -0
  442. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_clis.py +0 -0
  443. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_close_with_a_note.py +0 -0
  444. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cloud.py +0 -0
  445. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cloud_sources.py +0 -0
  446. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cloudfix.py +0 -0
  447. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_coding_session_continuity.py +0 -0
  448. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_completion_freshness.py +0 -0
  449. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_concierge_counsel.py +0 -0
  450. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_config.py +0 -0
  451. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_context.py +0 -0
  452. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_context_refresh_freshness.py +0 -0
  453. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_coordination.py +0 -0
  454. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_correction_doors.py +0 -0
  455. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel.py +0 -0
  456. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel_consumers.py +0 -0
  457. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel_migration.py +0 -0
  458. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_counsel_sections.py +0 -0
  459. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_current_restore.py +0 -0
  460. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_cwlogs_paging.py +0 -0
  461. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_danger_verdict.py +0 -0
  462. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_data_is_coding.py +0 -0
  463. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_databases.py +0 -0
  464. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_deps.py +0 -0
  465. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_desktop.py +0 -0
  466. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_devin.py +0 -0
  467. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_devtools.py +0 -0
  468. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_diff_review.py +0 -0
  469. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_digest_brief.py +0 -0
  470. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_dispatch_retries.py +0 -0
  471. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_docs_and_llm.py +0 -0
  472. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_docs_flow.py +0 -0
  473. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_docs_manifest.py +0 -0
  474. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_draft_choices.py +0 -0
  475. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_due_days.py +0 -0
  476. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_duplicate_connectors.py +0 -0
  477. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_edit_recipient.py +0 -0
  478. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_email_chains.py +0 -0
  479. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_email_identity_routing.py +0 -0
  480. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ending_keeps_the_write_up.py +0 -0
  481. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_evening_brief.py +0 -0
  482. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_every_card_is_reachable.py +0 -0
  483. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_every_cli_startable.py +0 -0
  484. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_exe_splash.py +0 -0
  485. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_factory.py +0 -0
  486. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_failed_acts.py +0 -0
  487. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_feed_lookups.py +0 -0
  488. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_feed_working.py +0 -0
  489. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_files.py +0 -0
  490. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_final_answer_capture.py +0 -0
  491. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_finished_chat_stays_finished.py +0 -0
  492. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_first_run_triage.py +0 -0
  493. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floating_assistant.py +0 -0
  494. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floor.py +0 -0
  495. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floor_bypasses.py +0 -0
  496. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_floor_wave_b.py +0 -0
  497. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_follow_up_verdict.py +0 -0
  498. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_fresh_evaluation.py +0 -0
  499. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_freshness.py +0 -0
  500. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_freshness_walk.py +0 -0
  501. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general_agent_permissions.py +0 -0
  502. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_general_knows_the_repos.py +0 -0
  503. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_github_auto.py +0 -0
  504. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_github_images.py +0 -0
  505. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_github_poll_scope.py +0 -0
  506. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goal_serves.py +0 -0
  507. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_api.py +0 -0
  508. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_promises.py +0 -0
  509. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_rail.py +0 -0
  510. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_goals_store.py +0 -0
  511. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_guard.py +0 -0
  512. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hand_task_checklist.py +0 -0
  513. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handbook_topics.py +0 -0
  514. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handoff_channels.py +0 -0
  515. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_handraise.py +0 -0
  516. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_harvest.py +0 -0
  517. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_held_ask_answers.py +0 -0
  518. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_histgen.py +0 -0
  519. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_home_is_never_yours.py +0 -0
  520. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hook_off_loop.py +0 -0
  521. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hook_token_file.py +0 -0
  522. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hooks_events.py +0 -0
  523. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_hooks_version.py +0 -0
  524. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_idea_verdicts.py +0 -0
  525. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_ignore_sender_quiets_its_work.py +0 -0
  526. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_images.py +0 -0
  527. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imap_catchup.py +0 -0
  528. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imap_history.py +0 -0
  529. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imapmail.py +0 -0
  530. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_imessage.py +0 -0
  531. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_inline_pictures.py +0 -0
  532. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_intacct.py +0 -0
  533. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_interrupted_work.py +0 -0
  534. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_invite_is_not_work.py +0 -0
  535. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_invoice_workflow.py +0 -0
  536. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_jev.py +0 -0
  537. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_judge_reads_the_conclusion.py +0 -0
  538. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_kind_dispatch.py +0 -0
  539. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_knowledge.py +0 -0
  540. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_knowledge_semantic.py +0 -0
  541. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_launch_key.py +0 -0
  542. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_launch_key_private.py +0 -0
  543. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_layer_profiles.py +0 -0
  544. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_learnedgraph.py +0 -0
  545. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lifespan_loops_are_guarded.py +0 -0
  546. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_linkedin.py +0 -0
  547. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_linkedin_signin.py +0 -0
  548. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_live.py +0 -0
  549. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_local_file.py +0 -0
  550. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lookup_limits.py +0 -0
  551. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_lookups.py +0 -0
  552. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mail_catchup.py +0 -0
  553. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mail_fetch_cost.py +0 -0
  554. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mail_folders.py +0 -0
  555. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mailauth.py +0 -0
  556. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mark_read.py +0 -0
  557. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_markets.py +0 -0
  558. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mcp.py +0 -0
  559. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_meeting_prep.py +0 -0
  560. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_message_thread.py +0 -0
  561. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_messengers.py +0 -0
  562. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_model_list.py +0 -0
  563. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_morning_line.py +0 -0
  564. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_msauth.py +0 -0
  565. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_mssql.py +0 -0
  566. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_multi_question.py +0 -0
  567. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_muse.py +0 -0
  568. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_net.py +0 -0
  569. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_new_task_from_words.py +0 -0
  570. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_new_walk_off_the_lifespan.py +0 -0
  571. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_no_dispatch_while_agent_runs.py +0 -0
  572. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_no_pydantic_v1.py +0 -0
  573. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_noop_ending.py +0 -0
  574. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_not_coding.py +0 -0
  575. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_note_retrieval.py +0 -0
  576. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_one_app_one_reason.py +0 -0
  577. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_one_instance.py +0 -0
  578. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_one_pty_one_geometry.py +0 -0
  579. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_only_your_own_thread.py +0 -0
  580. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_operations.py +0 -0
  581. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin.py +0 -0
  582. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_doors.py +0 -0
  583. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_launch.py +0 -0
  584. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_roads.py +0 -0
  585. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_origin_seed.py +0 -0
  586. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_outbox.py +0 -0
  587. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_outcomes.py +0 -0
  588. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_own_rows_no_reply.py +0 -0
  589. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pane_theme.py +0 -0
  590. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_people.py +0 -0
  591. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_people_pages.py +0 -0
  592. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_permit.py +0 -0
  593. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_person_name.py +0 -0
  594. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_agent_card.py +0 -0
  595. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_phone_follows_up.py +0 -0
  596. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_plain_failures.py +0 -0
  597. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbook_facts.py +0 -0
  598. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbook_setup.py +0 -0
  599. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_playbooks.py +0 -0
  600. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pm.py +0 -0
  601. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_lanes.py +0 -0
  602. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_overlap.py +0 -0
  603. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_parallel.py +0 -0
  604. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_poll_sources.py +0 -0
  605. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pr_comments.py +0 -0
  606. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_press_never_waits.py +0 -0
  607. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_problems.py +0 -0
  608. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_problems_dismiss.py +0 -0
  609. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_procedure_selection.py +0 -0
  610. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_processing_demo_replay.py +0 -0
  611. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_processing_ledger.py +0 -0
  612. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_profile_is_a_role.py +0 -0
  613. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_progress_without_markers.py +0 -0
  614. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_projects.py +0 -0
  615. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_prompt_images.py +0 -0
  616. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_prompt_sources.py +0 -0
  617. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_promptmap_and_catalog.py +0 -0
  618. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_proof_ci_proposals.py +0 -0
  619. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_protocol_marks.py +0 -0
  620. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_pypi_downloads.py +0 -0
  621. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_quickbooks.py +0 -0
  622. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_qwen.py +0 -0
  623. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_rail_decisions.py +0 -0
  624. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_rank.py +0 -0
  625. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_rate_limit.py +0 -0
  626. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_read_text.py +0 -0
  627. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_recent_closures.py +0 -0
  628. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reclassify.py +0 -0
  629. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_redact.py +0 -0
  630. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_redact_doors.py +0 -0
  631. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_remote_sections.py +0 -0
  632. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_always_drafts.py +0 -0
  633. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_attachments.py +0 -0
  634. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_envelope.py +0 -0
  635. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_leaves_by_smtp.py +0 -0
  636. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_loop_in.py +0 -0
  637. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_needs_a_correspondent.py +0 -0
  638. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_opens_at_once.py +0 -0
  639. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_sees_pictures.py +0 -0
  640. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_sources.py +0 -0
  641. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_target.py +0 -0
  642. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reply_voice.py +0 -0
  643. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_repo_choice_triage.py +0 -0
  644. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_alerts.py +0 -0
  645. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_deliver.py +0 -0
  646. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_delivery_gate.py +0 -0
  647. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_headline.py +0 -0
  648. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_one_road.py +0 -0
  649. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_prompt_isolation.py +0 -0
  650. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_report_refusal.py +0 -0
  651. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_research.py +0 -0
  652. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_research_more.py +0 -0
  653. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_restricted_cli.py +0 -0
  654. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_review_delivery_api.py +0 -0
  655. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_review_task.py +0 -0
  656. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_reviews.py +0 -0
  657. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_robinhood.py +0 -0
  658. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_routing_memory.py +0 -0
  659. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_s3_poll_paging.py +0 -0
  660. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_scopes.py +0 -0
  661. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_search.py +0 -0
  662. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_security_followups.py +0 -0
  663. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_seed_fits_a_tty.py +0 -0
  664. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_seeded_reports.py +0 -0
  665. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_selector_vocabulary.py +0 -0
  666. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_semantic.py +0 -0
  667. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_send_targets.py +0 -0
  668. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sender_history.py +0 -0
  669. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sender_trust.py +0 -0
  670. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sender_words.py +0 -0
  671. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sentjudge.py +0 -0
  672. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_artifacts.py +0 -0
  673. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_continuity.py +0 -0
  674. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_files.py +0 -0
  675. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_session_record.py +0 -0
  676. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_settings_defaults_json.py +0 -0
  677. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup_skill.py +0 -0
  678. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_setup_walk.py +0 -0
  679. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sheets_sharepoint.py +0 -0
  680. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_simplefin.py +0 -0
  681. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_slipped.py +0 -0
  682. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_social.py +0 -0
  683. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_someone_else_replied.py +0 -0
  684. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_soul_interview.py +0 -0
  685. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stand_ins_stay_out_of_code.py +0 -0
  686. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_startup_contract.py +0 -0
  687. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stay_open.py +0 -0
  688. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stay_open_doors.py +0 -0
  689. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_store_app_cli.py +0 -0
  690. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_store_hotpaths.py +0 -0
  691. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_store_pokes.py +0 -0
  692. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_floor_more.py +0 -0
  693. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_hub_wall.py +0 -0
  694. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_live_fixes.py +0 -0
  695. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_stranger_token.py +0 -0
  696. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_strip_signoff.py +0 -0
  697. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_sync_clock.py +0 -0
  698. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_table_context.py +0 -0
  699. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_taken_care_of.py +0 -0
  700. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_ask.py +0 -0
  701. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_checklist.py +0 -0
  702. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_controls_operations.py +0 -0
  703. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_footprint.py +0 -0
  704. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_identity.py +0 -0
  705. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_refs.py +0 -0
  706. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_task_tools.py +0 -0
  707. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_telegram_buttons.py +0 -0
  708. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_teller.py +0 -0
  709. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_the_exe_ships_what_the_wheel_ships.py +0 -0
  710. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_the_split_holds.py +0 -0
  711. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_toil.py +0 -0
  712. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_tracker_revisions.py +0 -0
  713. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_treg.py +0 -0
  714. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_cleanup.py +0 -0
  715. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_dataset.py +0 -0
  716. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_errors.py +0 -0
  717. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_guide.py +0 -0
  718. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_images.py +0 -0
  719. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_pr_rule.py +0 -0
  720. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_reads_not_guesses.py +0 -0
  721. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_retry_sweep.py +0 -0
  722. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_triage_sees_meetings.py +0 -0
  723. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_typed_words_press.py +0 -0
  724. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_update.py +0 -0
  725. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_update_refused.py +0 -0
  726. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_urgent_and_handoff.py +0 -0
  727. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_vault.py +0 -0
  728. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_verdict_paths.py +0 -0
  729. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_verdict_shape.py +0 -0
  730. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_verdict_sticks.py +0 -0
  731. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_vision.py +0 -0
  732. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_wabridge.py +0 -0
  733. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_wabridge_log_trim.py +0 -0
  734. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_waitroom.py +0 -0
  735. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_walk_follows_the_rail.py +0 -0
  736. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_walk_order.py +0 -0
  737. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_watermark.py +0 -0
  738. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_web_entrypoint.py +0 -0
  739. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_webguard.py +0 -0
  740. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_whatsapp_documents.py +0 -0
  741. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_whatsapp_images.py +0 -0
  742. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_whoami.py +0 -0
  743. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_withdrawn.py +0 -0
  744. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_witness.py +0 -0
  745. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_brief.py +0 -0
  746. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_events.py +0 -0
  747. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_resumes.py +0 -0
  748. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_scenarios.py +0 -0
  749. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_worker_surfaces.py +0 -0
  750. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_workerstate_said.py +0 -0
  751. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_xlsx_report_headers.py +0 -0
  752. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_lastword.py +0 -0
  753. {taskuary-0.3.9.2 → taskuary-0.3.9.4}/tests/test_zz_setupchat.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskuary
3
- Version: 0.3.9.2
3
+ Version: 0.3.9.4
4
4
  Summary: Your work manager. Locally. Securely. In control. Mail, chats and tickets in one list; your agents do the work, you approve. Runs on your machine.
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/ldbumble/taskuary
@@ -71,7 +71,7 @@ Dynamic: license-file
71
71
 
72
72
  [![CI](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml/badge.svg)](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml)
73
73
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/ldbumble/taskuary/badge)](https://scorecard.dev/viewer/?uri=github.com/ldbumble/taskuary)
74
- [![PyPI](https://img.shields.io/pypi/v/taskuary.svg?cacheSeconds=300&release=0.3.9.2&asof=2026-10-16T1300)](https://pypi.org/project/taskuary/)
74
+ [![PyPI](https://img.shields.io/pypi/v/taskuary.svg?cacheSeconds=300&release=0.3.9.4&asof=2026-10-18T1200)](https://pypi.org/project/taskuary/)
75
75
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776ab.svg)](https://github.com/ldbumble/taskuary)
76
76
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
77
77
  [![Stars](https://img.shields.io/github/stars/ldbumble/taskuary?style=flat&color=d4a72c&label=%E2%98%85%20stars)](https://github.com/ldbumble/taskuary/stargazers)
@@ -82,11 +82,9 @@ Dynamic: license-file
82
82
 
83
83
  **A personal AI assistant for your job.** Mail, chats and tickets become tasks, the agents you already use (Claude Code, Codex, Gemini) do the work, and nothing goes out until you approve. Open source, runs on your machine, no subscription.
84
84
 
85
- Compared with hosted assistants like Fyxer, Taskuary is free and open source, runs on your machine, and hands the work to agents you already use.
86
-
87
85
  ![The Assistant's Game view: an office where every task, message and agent is a figure, opening on the whole floor and zooming into each room - the Agent Floor, the Meeting Room where people wait on you, the Gym, the Coffee Room, the Memory Archive, and the Assistant Core.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/hero.webp?v=smooth)
88
86
 
89
- Taskuary is early—currently **v0.3.9.2**—so breaking changes are still possible before 1.0.
87
+ Taskuary is early—currently **v0.3.9.4**—so breaking changes are still possible before 1.0.
90
88
 
91
89
  <p align="center">
92
90
  <a href="https://taskuary.com/demo/"><img
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![CI](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml/badge.svg)](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml)
6
6
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/ldbumble/taskuary/badge)](https://scorecard.dev/viewer/?uri=github.com/ldbumble/taskuary)
7
- [![PyPI](https://img.shields.io/pypi/v/taskuary.svg?cacheSeconds=300&release=0.3.9.2&asof=2026-10-16T1300)](https://pypi.org/project/taskuary/)
7
+ [![PyPI](https://img.shields.io/pypi/v/taskuary.svg?cacheSeconds=300&release=0.3.9.4&asof=2026-10-18T1200)](https://pypi.org/project/taskuary/)
8
8
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776ab.svg)](https://github.com/ldbumble/taskuary)
9
9
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
10
  [![Stars](https://img.shields.io/github/stars/ldbumble/taskuary?style=flat&color=d4a72c&label=%E2%98%85%20stars)](https://github.com/ldbumble/taskuary/stargazers)
@@ -15,11 +15,9 @@
15
15
 
16
16
  **A personal AI assistant for your job.** Mail, chats and tickets become tasks, the agents you already use (Claude Code, Codex, Gemini) do the work, and nothing goes out until you approve. Open source, runs on your machine, no subscription.
17
17
 
18
- Compared with hosted assistants like Fyxer, Taskuary is free and open source, runs on your machine, and hands the work to agents you already use.
19
-
20
18
  ![The Assistant's Game view: an office where every task, message and agent is a figure, opening on the whole floor and zooming into each room - the Agent Floor, the Meeting Room where people wait on you, the Gym, the Coffee Room, the Memory Archive, and the Assistant Core.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/hero.webp?v=smooth)
21
19
 
22
- Taskuary is early—currently **v0.3.9.2**—so breaking changes are still possible before 1.0.
20
+ Taskuary is early—currently **v0.3.9.4**—so breaking changes are still possible before 1.0.
23
21
 
24
22
  <p align="center">
25
23
  <a href="https://taskuary.com/demo/"><img
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "taskuary"
7
- version = "0.3.9.2"
7
+ version = "0.3.9.4"
8
8
  description = "Your work manager. Locally. Securely. In control. Mail, chats and tickets in one list; your agents do the work, you approve. Runs on your machine."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -11,8 +11,9 @@ a per-hour cap, the light gear, a small prompt, the bigger read only for the ite
11
11
  import hashlib, json, re, threading
12
12
  from datetime import datetime, timedelta
13
13
  from loguru import logger
14
- from . import concierge
14
+ from . import buttons, concierge
15
15
  from .llm import build_llm, ask_json
16
+ L = buttons.label # the prompt names a button by its one label (buttons.json)
16
17
 
17
18
  ON_KEY, CAP_KEY, CAP_DEFAULT = 'advisor_events', 'advisor_event_cap', 30
18
19
  BACKGROUND = True # the suite turns this off (tests/conftest.py): a judgement runs only when a test asks for it inline
@@ -24,6 +25,12 @@ def target_of(store, key: str):
24
25
  """A rail key -> (target kind, id), or None for a key with nothing to advise on (a connection, a meeting, a batch)."""
25
26
  m = re.match(r'^(task|agent|wrap|msg|report):(\d+)$', str(key or ''))
26
27
  if m: return ('task' if m.group(1) in ('task', 'agent', 'wrap') else 'message', int(m.group(2)))
28
+ # a draft waiting for your yes is keyed by its review (funnel's review:N, in a bare store and the demo): advised as the
29
+ # task it answers for, else the message - read as "nothing to advise on", every draft on the demo's rail had an empty bar
30
+ m = re.match(r'^review:(\d+)$', str(key or ''))
31
+ if m:
32
+ r = store.get_review(int(m.group(1))) or {}
33
+ return ('task', int(r['TaskId'])) if r.get('TaskId') else ('message', int(r['MessageId'])) if r.get('MessageId') else None
27
34
  if str(key or '').startswith('processing:'):
28
35
  # the inventory's key names an ITEM; its members say what it is made of (a task outranks its mail rows)
29
36
  try:
@@ -55,9 +62,30 @@ def _write(store, *, target_kind, target_id, key, event, revision, tier=1, line=
55
62
  'VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
56
63
  (target_kind, int(target_id), key, event, revision, int(tier), line or '', verb, label, json.dumps(list(count)),
57
64
  json.dumps(list(evidence)), model, dropped, _now()))
58
- def row(store, target_kind: str, target_id, revision: str):
59
- return store._one('SELECT * FROM advice WHERE TargetKind=? AND TargetId=? AND Revision=? ORDER BY Tier DESC, Id DESC LIMIT 1',
60
- (target_kind, int(target_id), revision))
65
+ # A drop for an OUTSIDE reason is not a verdict on the item: with no AI, opening an item wrote "no brain" and the line never
66
+ # came once one was connected; 30 reads in an hour left every later item a "cap" for good (2026-10-17 audit). The next look
67
+ # tries again. "nothing to say", "verb not offered", "no item", "no actions" stand for the revision.
68
+ RETRY = ('no brain', 'cap', 'no answer')
69
+ def retryable(r) -> bool: return bool(r) and not r.get('Verb') and str(r.get('Dropped') or '').startswith(RETRY)
70
+ def _at(store, target_kind, target_id, revision, own=None) -> list:
71
+ """The rows at this revision - only those written for the item whose keys are `own`, when given."""
72
+ rs = store._rows('SELECT * FROM advice WHERE TargetKind=? AND TargetId=? AND Revision=? ORDER BY Id DESC', (target_kind, int(target_id), revision))
73
+ return rs if own is None else [r for r in rs if r.get('Key') in own]
74
+ def row(store, target_kind: str, target_id, revision: str, own=None):
75
+ """The row that stands at this revision: the newest with a verb at any tier - a later tier-2 drop sorted first by tier hid
76
+ a good tier-1 line - else the newest verdict. Retryable drops are never it."""
77
+ rs = _at(store, target_kind, target_id, revision, own)
78
+ return next((r for r in rs if r.get('Verb')), None) or next((r for r in rs if not retryable(r)), None)
79
+
80
+
81
+ # ADVICE IS KEYED TO ITS ITEM: one task can stand on the rail twice - its draft (review:N) and its agent (agent:N) - and a line
82
+ # written for one, with a verb only that one's row carries, stood over the other (2026-10-18). A row belongs to the item it was
83
+ # judged as: its rail key, or a key that names that same item (its aliases: task:N for the processing inventory's key).
84
+ def keys_of(item: dict | None, key: str = None) -> set:
85
+ return {k for k in (key, *((item or {}).get('key'), *((item or {}).get('aliases') or []))) if k}
86
+ def _own(store, tgt, key: str, rs: list) -> set:
87
+ """The keys whose rows are `key`'s - read off the item only when a row at this revision was written under another key."""
88
+ return {key} if all(r.get('Key') == key for r in rs) else keys_of(_item(store, *tgt, key=key), key)
61
89
  def rows(store, target_kind: str, target_id, limit: int = 10) -> list:
62
90
  return store._rows('SELECT * FROM advice WHERE TargetKind=? AND TargetId=? ORDER BY Id DESC LIMIT ?', (target_kind, int(target_id), limit))
63
91
 
@@ -69,7 +97,8 @@ SYSTEM = (
69
97
  "the item's own facts point at one verb. Never invent a number: the numbers in the ledger lines are the only ones you may use, "
70
98
  "and you cite their ids. A ledger line says what HAPPENED, never whether it worked: \"continued\" means the session was started "
71
99
  "again, nothing more - never call it a success, and never say something was merged, sent or fixed unless a line says exactly that. "
72
- "The line is plain words for the owner: the ids go in \"evidence\" only, and the verb is named by its label, never its id. "
100
+ "The line is plain words for the owner, who may never have written code: the ids go in \"evidence\" only, the verb is named by "
101
+ "its label, never its id, and never a word from the item's own bookkeeping (lane, kind, triage, session, model, an event name). "
73
102
  "The reason must be the fact that makes THIS verb right, and it must hold up on its own: someone or an agent waiting on the "
74
103
  "owner is a reason to answer, never a reason to put it off. Ending an agent's session is right when its work is done or no "
75
104
  "longer wanted; when it has finished something for the owner to review or send, the move is the one that reviews or sends it. If none of the verbs offered is the right move, say nothing - a "
@@ -77,8 +106,18 @@ SYSTEM = (
77
106
  "Answer with JSON only:{\"verb\": \"<one of the verbs>\" or null, \"line\": \"<sentence>\" or \"\", "
78
107
  "\"evidence\": [\"<ids from the lines below>\"]}. "
79
108
  "EXCEPT when the EVENT is item.shown: the owner is looking at this item right now and is owed a next step, so pick the verb the "
80
- "item's own facts make right (a person waiting on them: answer; nothing for them to do: close or let go; work an agent left: "
81
- "continue or review it) and say why in plain words - say nothing only when no verb offered fits at all.")
109
+ f"item's own facts make right (a person waiting on them: {L('reply')}; an agent asking them something: {L('answer_agent')}; nothing "
110
+ f"for them to do: {L('close')} or {L('let_go')}; work an agent left: {L('continue')} or {L('approve')}; a draft waiting: {L('approve')}; "
111
+ f"a reply already sent - sending never closes the task - and nothing left to do: {L('close')}; a reply that failed to "
112
+ "send: the fix offered with it) - whichever of those is "
113
+ "OFFERED - and say why in plain words - say nothing only when no verb offered fits at all.")
114
+ def _system(store) -> str:
115
+ """SYSTEM plus the owner's own Voice section of COUNSEL: the Advisor's line sits in the same box as the chat's, so it
116
+ speaks by the same rules - it never had them, and said "lane" and "session" to a finance user (2026-10-17 audit)."""
117
+ from . import counsel
118
+ try: voice = counsel.sections(counsel.load(store)).get(counsel.VOICE_HEAD, '').strip()
119
+ except Exception: voice = ''
120
+ return f"{SYSTEM}\n\nHOW THE LINE SPEAKS (the owner's own rules):\n{voice}" if voice else SYSTEM
82
121
  # the event every item on the table gets, when no other event judged it at its current revision (Advisor audit, 2026-10-15)
83
122
  SHOWN = 'item.shown'
84
123
  WANT = {'type': 'object', 'properties': {'verb': {'type': ['string', 'null']}, 'line': {'type': 'string'},
@@ -86,9 +125,10 @@ WANT = {'type': 'object', 'properties': {'verb': {'type': ['string', 'null']}, '
86
125
  _EV = re.compile(r'^(out|mem|rv|task)\d+$')
87
126
 
88
127
 
89
- def _item(store, target_kind, target_id):
90
- """The card the rail would show for this target - found by its task or message id, since the rail's key spelling is the
91
- processing inventory's (`processing:...`) in a real install and a legacy alias in a bare store."""
128
+ def _item(store, target_kind, target_id, key: str = None):
129
+ """The card the rail would show for this target - the one keyed `key` when asked for an item (keys_of), else found by its task
130
+ or message id, since the rail's key spelling is the processing inventory's (`processing:...`) in a real install and a legacy
131
+ alias in a bare store."""
92
132
  from . import funnel
93
133
  if target_kind == 'task':
94
134
  t = store.get_task(target_id) or {}
@@ -98,7 +138,9 @@ def _item(store, target_kind, target_id):
98
138
  items = (funnel.full_items(store) or []) + pile # read items kept: the one on the table is often read
99
139
  except Exception: items = []
100
140
  f = 'tid' if target_kind == 'task' else 'mid'
101
- return next((i for i in items if i.get(f) == int(target_id)), None) or funnel.item_for_key(store, key_of(target_kind, target_id))
141
+ mine = [i for i in items if i.get(f) == int(target_id)]
142
+ return (next((i for i in mine if key and key in keys_of(i)), None) or next(iter(mine), None)
143
+ or funnel.item_for_key(store, key_of(target_kind, target_id)))
102
144
 
103
145
 
104
146
  def habit(store, verb: str, item: dict) -> tuple:
@@ -112,6 +154,15 @@ def habit(store, verb: str, item: dict) -> tuple:
112
154
  lambda r: json.loads(r['f'] or '{}').get('answer_days') is not None)}.get(verb)
113
155
  if not q: return (0, 0)
114
156
  rs = store._rows(q[0]); return (sum(1 for r in rs if q[1](r)), len(rs))
157
+ # ...and what each count MEASURES, said so: "You chose Mark done 2 of 3 times in a moment like this" was read off closes that
158
+ # held and answers to nudges, counted over every item, not this kind of moment (2026-10-17 audit)
159
+ MEASURES = {'continue': 'You picked the work back up {n} of the last {m} times an agent stopped',
160
+ 'approve': 'You sent {n} of your last {m} drafts as written',
161
+ 'close': '{n} of the last {m} tasks you closed stayed closed',
162
+ 'chase': '{n} of your last {m} nudges got an answer'}
163
+ def says(verb: str, count) -> str:
164
+ n, m = (list(count) + [0, 0])[:2]
165
+ return MEASURES[verb].format(n=n, m=m) + '.' if verb in MEASURES and m >= 2 else ''
115
166
  def pill(label: str, count) -> str:
116
167
  n, m = (list(count) + [0, 0])[:2]
117
168
  return f'{label} · {n} of {m} times' if m >= 2 else str(label or '')
@@ -120,7 +171,12 @@ def pill(label: str, count) -> str:
120
171
  def _prompt(store, event, item, verbs, tier, target_kind, target_id) -> str:
121
172
  from .learn import injectable
122
173
  from . import outcomes
123
- facts = {k: item.get(k) for k in ('ref', 'kind', 'lane', 'title', 'who', 'when', 'why', 'channel') if item.get(k)}
174
+ from . import funnel
175
+ facts = {k: item.get(k) for k in ('ref', 'title', 'who', 'when', 'why', 'channel') if item.get(k)}
176
+ # where it stands, in the rail's own words - a lane id handed over as-is came back in the line ("the lane is blocked")
177
+ kinds = {k['key']: k['word'] for k in funnel._VOCAB['kinds']}
178
+ stands = kinds.get(item.get('kind')) or funnel.LANE_WORDS.get(item.get('lane'), ('',))[0]
179
+ if stands: facts['where it stands'] = stands
124
180
  lines = [f'EVENT: {event}', 'THE ITEM: ' + json.dumps(facts), f"PREVIEW: {str(item.get('preview') or '')[:300]}",
125
181
  'VERBS OFFERED: ' + ', '.join(f"{v['verb']} ({v['label']})" for v in verbs)]
126
182
  if target_kind == 'task':
@@ -139,7 +195,7 @@ def _prompt(store, event, item, verbs, tier, target_kind, target_id) -> str:
139
195
  at = continuity.last_agent_turn(store, int(target_id))
140
196
  mail = continuity.mail_since(store, int(target_id), at) if at else []
141
197
  if mail:
142
- lines.append(f"NEW SINCE THE AGENT'S LAST TURN ({at}) - its saved conversation is from BEFORE these; Continue session hands "
198
+ lines.append(f"NEW SINCE THE AGENT'S LAST TURN ({at}) - its saved conversation is from BEFORE these; Keep going hands "
143
199
  "them to it first:\n" + '\n'.join(f"- {m.get('FromName') or m.get('FromEmail')} ({m.get('CreatedAt')}): {m.get('Subject') or ''}"
144
200
  f" - {' '.join(str(m.get('BodyText') or '').split())[:500]}" for m in mail[-3:]))
145
201
  t = store.get_task(int(target_id)) or {}
@@ -149,7 +205,7 @@ def _prompt(store, event, item, verbs, tier, target_kind, target_id) -> str:
149
205
  lrn = injectable(store.doc('learned') or '')
150
206
  if lrn.strip(): lines.append('LEARNED (the owner, from their own verdicts):\n' + lrn[:2000])
151
207
  led = [f"out{r['Id']}: {outcomes._sentence(store, r)}" for r in outcomes.rows_for(store, target_kind, target_id) if r.get('ResolvedAt')][:5]
152
- led += [f"{v['verb']}: this move {n} of {m} times" for v in verbs for n, m in [habit(store, v['verb'], item)] if m >= 2]
208
+ led += [f"{v['label']}: {says(v['verb'], c)}" for v in verbs for c in [habit(store, v['verb'], item)] if says(v['verb'], c)]
153
209
  if led: lines.append('THE OUTCOME LEDGER (what came of actions like this):\n' + '\n'.join(led))
154
210
  if tier >= 2: # the bigger read, only for the item on the table
155
211
  from .counsel import dossier
@@ -173,27 +229,39 @@ def plain(line: str, verb: str, label: str) -> str:
173
229
 
174
230
 
175
231
  def _offered(verbs: list, said: str):
176
- """The verb the model named, as the prompt listed it: "approve (Send & close)" copied whole, the bare id, or the label alone -
232
+ """The verb the model named, as the prompt listed it: "approve (Send)" copied whole, the bare id, or the label alone -
177
233
  an exact-id match dropped three right answers as "verb not offered" (2026-10-13)."""
178
234
  w = ' '.join(str(said or '').split()).lower(); bare = re.sub(r'\s*\(.*\)\s*$', '', w)
179
235
  return next((v for v in verbs if w in (v['verb'].lower(), f"{v['verb']} ({v['label']})".lower(), str(v['label']).lower())
180
236
  or bare == v['verb'].lower()), None)
181
237
 
182
238
 
183
- def judge(store, event: str,target_kind: str, target_id, rev: str, tier: int = 1, llm=None) -> int:
184
- key = key_of(target_kind, target_id)
239
+ def judge(store, event: str,target_kind: str, target_id, rev: str, tier: int = 1, llm=None, key: str = None) -> int:
240
+ """Judge one item at one revision - the item keyed `key` when the strip asked for it, else the target's first card - and
241
+ write the row under that item's own key (keys_of), so it is never read back over another item of the same task."""
242
+ item = _item(store, target_kind, target_id, key)
243
+ key = (item or {}).get('key') or key or key_of(target_kind, target_id)
244
+ own = keys_of(item, key)
185
245
  def W(**kw): return _write(store, target_kind=target_kind, target_id=target_id, key=key, event=event, revision=rev, tier=tier, **kw)
186
- item = _item(store, target_kind, target_id)
187
246
  if not item: return W(dropped='no item')
188
- verbs = [c for c in concierge.chips_for(store, item) if c.get('verb') != 'next']
247
+ if quiet(item): return W(dropped='left to the item')
248
+ verbs = offered(store, item)
189
249
  if not verbs: return W(dropped='no actions')
250
+ have = row(store, target_kind, target_id, rev, own) # two events in one poll: the second finds the first's row
251
+ if judged(have, tier): return have['Id']
190
252
  brain = llm or build_llm(store)
191
- if not brain: return W(dropped='no brain')
192
- have = row(store, target_kind, target_id, rev) # two events in one poll: the second finds the first's row
193
- if have and int(have.get('Tier') or 1) >= tier: return have['Id']
253
+ if not brain:
254
+ # once per revision, and said: the strip asks for an AI (for_key's {"none": "no_ai"}) - a repeat would loop the re-read
255
+ last = next(iter(_at(store, target_kind, target_id, rev, own)), None)
256
+ if last and last.get('Dropped') == 'no brain': return last['Id']
257
+ rid = W(dropped='no brain'); _emit(key, target_kind, target_id); return rid
194
258
  model = getattr(brain, 'last_pick', None) or getattr(brain, 'model', None) or 'light'
195
- ans = ask_json(brain, SYSTEM, _prompt(store, event, item, verbs, tier, target_kind, target_id), want=WANT, max_tokens=200)
259
+ ans = ask_json(brain, _system(store), _prompt(store, event, item, verbs, tier, target_kind, target_id), want=WANT, max_tokens=200)
196
260
  d = ans.data if isinstance(ans.data, dict) else {}
261
+ # a line that landed while this one was thinking stands: a tier-2 answer, drop or not, never replaces a line the owner may
262
+ # already be reaching for (B5 - the filled button moved under the cursor seconds after the item opened)
263
+ now = row(store, target_kind, target_id, rev, own)
264
+ if now and now.get('Verb'): return now['Id']
197
265
  if not d: return W(dropped=f'no answer: {ans.error or "not an object"}'[:200], model=model)
198
266
  verb, line = d.get('verb'), ' '.join(str(d.get('line') or '').split())[:200]
199
267
  ev = [e for e in (d.get('evidence') or []) if isinstance(e, str) and _EV.match(e)][:6]
@@ -203,11 +271,58 @@ def judge(store, event: str,target_kind: str, target_id, rev: str, tier: int = 1
203
271
  if not hit: return W(dropped=f'verb not offered: {verb}'[:120], model=model, line=line, evidence=ev)
204
272
  line = plain(line, verb, hit['label'])
205
273
  rid = W(line=line, verb=verb, label=hit['label'],count=habit(store, verb, item), evidence=ev, model=model)
274
+ _emit(key, target_kind, target_id); return rid
275
+
276
+
277
+ def _emit(key, target_kind, target_id):
206
278
  try:
207
279
  from . import live
208
280
  live.emit(live.ADVICE, key=key, target_kind=target_kind, target_id=int(target_id))
209
281
  except Exception: pass
210
- return rid
282
+
283
+
284
+ def judged(have, tier: int) -> bool:
285
+ """A line stands at any tier (the bigger read runs only where the first one found none); a verdict drop stands for its own
286
+ tier and below, so the item on the table still earns the bigger read after the small one said nothing."""
287
+ return bool(have) and (bool(have.get('Verb')) or int(have.get('Tier') or 1) >= tier)
288
+
289
+
290
+ def quiet(item: dict) -> bool:
291
+ """Where the Advisor keeps out of it. Mail the AI never sorted: the row's own Sort it again is the move, and the Advisor,
292
+ offered only Make a task / Send to agent / Not ours, put the dark button on "Not ours" for mail nobody read. A report that
293
+ ran fine: it is read, not acted on, and the only verbs it carries create work (2026-10-17 audit)."""
294
+ return item.get('lane') == 'unjudged' or (item.get('kind') == 'report' and not item.get('bad'))
295
+
296
+
297
+ def delivery_fix(store, item: dict) -> dict | None:
298
+ """{label, href} of the place that fixes the item's failed send - the draft's envelope (Deliver.fix, kept across a reload),
299
+ else the newest act on the item when it failed with one (OutcomeJson.fix). None when nothing failed, or it named no place."""
300
+ ok = lambda f: f if isinstance(f, dict) and f.get('label') and f.get('href') else None
301
+ r = (store.get_review(int(item['rid'])) if item.get('rid') else None) or {}
302
+ try: env = json.loads(r.get('Deliver') or '{}') or {}
303
+ except (TypeError, ValueError): env = {}
304
+ if isinstance(env, dict) and (r.get('DeliveryState') or env.get('delivery')) == 'failed' and ok(env.get('fix')): return ok(env['fix'])
305
+ try: ops = store.operations_for(item.get('tid'), [item['mid']] if item.get('mid') else [])
306
+ except Exception: ops = []
307
+ last = ops[-1] if ops else {}
308
+ try: out = json.loads(last.get('OutcomeJson') or '{}') if last.get('Status') == 'error' else {}
309
+ except (TypeError, ValueError): out = {}
310
+ return ok((out or {}).get('fix')) if isinstance(out, dict) else None
311
+
312
+
313
+ def offered(store, item: dict) -> list:
314
+ """THE ITEM'S REAL BUTTONS, AND NOTHING IT CANNOT DO: the verbs its row carries minus Next - chips_for, which already drops
315
+ what this install cannot do (capabilities.py: no Send on a draft whose channel cannot send, no coding agent with no
316
+ coding tool) - plus the row's own fix when a send failed and named the place that fixes it, under that place's own name.
317
+ An agent waiting on the owner carries Answer it there (chips_for) - its card once offered only End and Remind me, which the
318
+ prompt forbids for someone waiting, so the Advisor stood silent (2026-10-17 audit). Not added here: a paused, stalled or
319
+ stopped agent has nobody listening, and the row knows which is which."""
320
+ verbs = [c for c in concierge.chips_for(store, item) if c.get('verb') != 'next']
321
+ try: fix = delivery_fix(store, item)
322
+ except Exception as e:
323
+ logger.debug(f'advisor: no fix read for {item.get("key")} - {e}'); fix = None
324
+ # the fix leads: a send that failed is fixed before it is sent again (ReviewDecision.jsx draws it as '<rid>:fix')
325
+ return ([buttons.chip('fix') | {'label': fix['label'], 'href': fix['href']}] if fix else []) + verbs
211
326
 
212
327
 
213
328
  def _capped(store) -> bool:
@@ -220,27 +335,31 @@ def _capped(store) -> bool:
220
335
  _INFLIGHT, _LOCK = set(), threading.Lock() # (kind, id, revision, tier) being judged right now
221
336
 
222
337
 
223
- def notice(store, event: str, target_kind: str, target_id, *, tier: int = 1, wait: bool = False, llm=None):
224
- """The one door every event calls. Never raises: a hook, a close or a poll must not fail for advice.
338
+ def notice(store, event: str, target_kind: str, target_id, *, tier: int = 1, wait: bool = False, llm=None, key: str = None):
339
+ """The one door every event calls. Never raises: a hook, a close or a poll must not fail for advice. `key` is the item the
340
+ strip asked for (for_key): only that item's rows count as judged. An event names a target, and any row at its revision does.
225
341
  Returns the row id when judged inline (tests, `wait=True`), None when skipped or sent to the background."""
226
342
  try:
227
343
  if str(store.get_setting(ON_KEY, '1') or '1') != '1' or not target_id: return None
228
344
  rev = revision(store, target_kind, target_id)
229
- have = row(store, target_kind, target_id, rev)
230
- if have and int(have.get('Tier') or 1) >= tier: return None # judged at this revision already
231
- if _capped(store): return _write(store, target_kind=target_kind, target_id=target_id, key=key_of(target_kind, target_id), event=event, revision=rev, tier=tier, dropped='cap')
232
- mark = (target_kind, int(target_id), rev, int(tier))
345
+ own = _own(store, (target_kind, target_id), key, _at(store, target_kind, target_id, rev)) if key else None
346
+ if judged(row(store, target_kind, target_id, rev, own), tier): return None # judged at this revision already
347
+ if _capped(store):
348
+ last = next(iter(_at(store, target_kind, target_id, rev, own)), None)
349
+ if last and last.get('Dropped') == 'cap': return last['Id'] # one cap row per revision, retried next look
350
+ return _write(store, target_kind=target_kind, target_id=target_id, key=key or key_of(target_kind, target_id), event=event, revision=rev, tier=tier, dropped='cap')
351
+ mark = (target_kind, int(target_id), rev, int(tier), key)
233
352
  with _LOCK:
234
353
  if mark in _INFLIGHT: return None # the same moment, judged on another thread
235
354
  _INFLIGHT.add(mark)
236
355
  def done():
237
356
  with _LOCK: _INFLIGHT.discard(mark)
238
357
  if wait:
239
- try: return judge(store, event, target_kind, target_id, rev, tier, llm)
358
+ try: return judge(store, event, target_kind, target_id, rev, tier, llm, key)
240
359
  finally: done()
241
360
  if not BACKGROUND: done(); return None
242
361
  def go():
243
- try: judge(store, event, target_kind, target_id, rev, tier, llm)
362
+ try: judge(store, event, target_kind, target_id, rev, tier, llm, key)
244
363
  except Exception as e: logger.warning(f'advisor: {event} on {target_kind} {target_id} not judged - {e}')
245
364
  finally: done()
246
365
  threading.Thread(target=go, daemon=True, name=f'advise-{target_kind}-{target_id}').start()
@@ -250,8 +369,13 @@ def notice(store, event: str, target_kind: str, target_id, *, tier: int = 1, wai
250
369
 
251
370
  def _payload(r: dict) -> dict:
252
371
  count = json.loads(r.get('CountJson') or '[0,0]')
253
- return {'key': r['Key'], 'line': plain(r['Line'] or '', r['Verb'] or '', r['Label'] or '') if r.get('Line') else r.get('Line'), 'verb': r['Verb'], 'label': r['Label'], 'pill': pill(r['Label'], count), 'count': count,
254
- 'evidence': json.loads(r.get('EvidenceJson') or '[]'), 'revision': r['Revision'], 'tier': r['Tier'], 'at': r['CreatedAt']}
372
+ # a row judged under an older wording ("Take it myself", "Close out") shows today's name; a state's name (Approve) is kept
373
+ verb = concierge.canon_verb(r['Verb']) if r.get('Verb') else r.get('Verb')
374
+ if r.get('Verb') and not verb: r = {**r, 'Line': ''} # its button is gone (Prep me): the line pointed at nothing
375
+ # a fix is named by the place it opens ("Connect a mailbox"), never the generic button word
376
+ lbl = r['Label'] if r.get('Label') in buttons.labels() or (verb == 'fix' and r.get('Label')) else buttons.label(verb or '') or r.get('Label')
377
+ return {'key': r['Key'], 'line': plain(r['Line'] or '', r['Verb'] or '', lbl or '') if r.get('Line') else r.get('Line'), 'verb': verb, 'label': lbl, 'pill': pill(lbl, count), 'count': count,
378
+ 'says': says(r['Verb'] or '', count), 'evidence': json.loads(r.get('EvidenceJson') or '[]'), 'revision': r['Revision'], 'tier': r['Tier'], 'at': r['CreatedAt']}
255
379
 
256
380
 
257
381
  def _at_work(store, target_kind: str, target_id) -> bool:
@@ -265,16 +389,28 @@ def _at_work(store, target_kind: str, target_id) -> bool:
265
389
 
266
390
  def for_key(store, key: str) -> dict:
267
391
  """What the prompt box shows for the item on the table: the row at the item's CURRENT revision, or nothing. A changed
268
- item drops its old pill by this one comparison - no cleanup pass. The item on the table earns the bigger read, once."""
392
+ item drops its old pill by this one comparison - no cleanup pass. The item on the table earns the bigger read, once, and
393
+ only where the small read left no line: a tier-2 answer swapped the line and moved the filled button seconds after the item
394
+ opened, under the owner's hand (B5, 2026-10-17). {"none": "no_ai"} is the strip's cue to ask for an AI."""
269
395
  tgt = target_of(store, key)
270
396
  if not tgt or _at_work(store, *tgt): return {}
271
- rev = revision(store, *tgt); r = row(store, tgt[0], tgt[1], rev)
272
- if r and int(r.get('Tier') or 1) < 2: notice(store, r['Event'], tgt[0], tgt[1], tier=2)
397
+ rev = revision(store, *tgt); rs = _at(store, tgt[0], tgt[1], rev)
398
+ # only the rows written for THIS item (keys_of): a line judged over the same task's other card is not this one's
399
+ own = _own(store, tgt, key, rs); rs = [x for x in rs if x.get('Key') in own]; r = row(store, tgt[0], tgt[1], rev, own)
400
+ if r and r.get('Verb'):
401
+ out = _payload(r) | {'key': key}
402
+ # a fix is a place, not a proposal: the page opens its href where the row has no '<rid>:fix' of its own to press (a failed
403
+ # act with no draft on the table) - read live, so a fix already made carries no stale link
404
+ if out.get('verb') == 'fix':
405
+ try: f = delivery_fix(store, _item(store, *tgt, key=key) or {})
406
+ except Exception: f = None
407
+ if f: out['href'] = f['href']
408
+ return out
273
409
  # NEVER LEFT GUESSING (the owner, 2026-10-15: "the advisor ... should be guiding at all times never leaving it guessing"): only
274
410
  # eight events ever judged an item, so a fresh email or a task that moved since its last event had an empty bar for good. The
275
411
  # item on the table is judged now, at this revision, once - the line arrives by the `advice` live event the page already reads
276
- if not r: notice(store, SHOWN, tgt[0], tgt[1], tier=2)
277
- return _payload(r) if r and r.get('Verb') else {}
412
+ if not judged(r, 2): notice(store, r['Event'] if r else SHOWN, tgt[0], tgt[1], tier=2, key=key)
413
+ return {'none': 'no_ai'} if rs and rs[0].get('Dropped') == 'no brain' else {}
278
414
 
279
415
 
280
416
  def notes(store, key: str, limit: int = 10) -> list:
@@ -294,7 +430,22 @@ def notes(store, key: str, limit: int = 10) -> list:
294
430
  def block(store, item: dict) -> str:
295
431
  """The Advisor's line for the chat's system prompt, so 'why?' is answered from its evidence - a lookup, not a think."""
296
432
  d = for_key(store, (item or {}).get('key') or '') if item else {}
297
- if not d: return ''
298
- ev = ', '.join(d['evidence']) or 'the item itself'
433
+ if not d.get('verb'): return ''
434
+ # the button's name and what the evidence SAYS: "verb stop_agent; evidence: out13" was handed to the chat as-is, and came
435
+ # back to the owner in its answer (2026-10-17 audit)
436
+ ev = '; '.join(filter(None, (evidence_words(store, e) for e in d['evidence']))) or 'the item itself'
299
437
  return (f"THE ADVISOR'S LINE on this item (if the owner asks why, this is the answer; the numbers are the ledger's): "
300
- f"\"{d['line']}\" - the pill offers {d['pill']} (verb {d['verb']}); evidence: {ev}.")
438
+ f"\"{d['line']}\" - its button is {d['label']}" + (f" ({d['says']})" if d.get('says') else '') + f"; it rests on: {ev}.")
439
+
440
+
441
+ def evidence_words(store, ev_id: str) -> str:
442
+ """One evidence id as what it says: an outcome as the ledger's own sentence, anything else as the label it resolves to."""
443
+ try:
444
+ if str(ev_id).startswith('out'):
445
+ from . import outcomes
446
+ r = store._one('SELECT * FROM outcome WHERE Id=?', (int(ev_id[3:]),))
447
+ return outcomes._sentence(store, r) if r else ''
448
+ from .learnedgraph import _resolve
449
+ lbl = _resolve(store, ev_id).get('label')
450
+ return '' if lbl == ev_id else str(lbl or '')
451
+ except Exception: return ''
@@ -274,11 +274,11 @@ def signed_out_msg(name: str, why: str, cmd: str = '') -> str:
274
274
  The name that arrives here is the PROFILE's - every install ships one called `coding` - so the
275
275
  CLI is read off the command it runs, which is the rule cliinstall.recipe_for exists for. Told
276
276
  the profile name, _LOGIN_HOW.get('coding') missed every time and always had."""
277
- from . import cliinstall
277
+ from . import cliinstall, words
278
278
  cli = cliinstall.recipe_for(cmd) or name
279
279
  how = _LOGIN_HOW.get(cli, f"run `{cli}` and sign in again")
280
280
  return (f"{name} is signed out on this machine ({why.strip()[:160]}). Press Set it up on "
281
- f"Connections > AI CLI agents and sign in there in the pane that opens - or {how} in a terminal.")
281
+ f"{words.name('ai_apps')} and sign in there in the pane that opens - or {how} in a terminal.")
282
282
 
283
283
 
284
284
  # Windows refuses to START some installs rather than failing inside them, and says only
@@ -451,6 +451,12 @@ def _codex_tool(item: dict):
451
451
  return None
452
452
 
453
453
 
454
+ def coding_ready(store) -> bool:
455
+ """CODING EXISTS ONLY WHERE A CODING TOOL CAN START (the owner, 2026-10-16: "if no cli tool like cloud api tools no coding"):
456
+ a connected CLI whose command runs on this computer. A ChatGPT sign-in or an API card - HIPAA AI included - is no coding tool."""
457
+ return any(runs_here(conn) for _key, conn in connection_brains(store))
458
+
459
+
454
460
  def runs_here(profile: dict) -> bool:
455
461
  """Does this profile's command resolve to something we can start?"""
456
462
  try: return bool(_resolve_cmd((profile or {}).get('cmd') or 'claude'))
@@ -699,7 +705,7 @@ def roster_line(store, a: dict) -> tuple:
699
705
  try: prof = json.loads(a.get('Config') or '{}')
700
706
  except ValueError: prof = {}
701
707
  if prof.get('triage_enabled') is False:
702
- return '', 'not offered to the router - "Available to triage" is off', 'not_offered'
708
+ return '', 'not offered new work - "Can be given new work from your mail" is off', 'not_offered'
703
709
  purpose = profile_purpose(a['Name'], prof, a.get('Kind') or 'coding')
704
710
  if not purpose: return '', 'no purpose set - triage has nothing to choose it by', 'no_purpose'
705
711
  if len(purpose) > ROSTER_PURPOSE_MAX: purpose = purpose[:ROSTER_PURPOSE_MAX - 1].rstrip() + '…'
@@ -1041,7 +1047,7 @@ def run_acp(profile: dict, prompt: str, trace, resume: str = None, cancel=None,
1041
1047
  if profile.get('model'):
1042
1048
  from .climodels import split_pick
1043
1049
  model, _ = split_pick(profile['model'])
1044
- cmd += [profile.get('model_arg') or '--model', model]
1050
+ if model: cmd += [profile.get('model_arg') or '--model', model]
1045
1051
  cwd = profile.get('cwd')
1046
1052
  trace('prompt', 'prompt_sent_to_agent', prompt)
1047
1053
  trace('tool', 'cli', f'{name} over acp cwd={cwd or os.getcwd()}' + (f' resume={resume}' if resume else ''))
@@ -1136,7 +1142,8 @@ def run_cli(profile: dict, prompt: str, trace, resume: str = None, cancel=None,
1136
1142
  from .climodels import split_pick
1137
1143
  from .climodels import effort_args
1138
1144
  m, eff = split_pick(profile['model'])
1139
- cmd += [profile.get('model_arg') or '--model', m] + effort_args(_cli_name(name), eff)
1145
+ # '@high' is the CLI's own model at that effort (a workflow's effort alone, workflows.brain): no empty model flag
1146
+ cmd += ([profile.get('model_arg') or '--model', m] if m else []) + effort_args(_cli_name(name), eff)
1140
1147
  # A CONVERSATION KEPT OPEN: the Assistant and the general agent name theirs (`keep_alive`), and claude's
1141
1148
  # stream-json input serves every turn from one process instead of starting the CLI per call (clipool).
1142
1149
  keep = profile.get('keep_alive')
@@ -13,7 +13,7 @@ And "Done" is a plain close - no report, no proposals, no reply draft; the conne
13
13
  result is the report.
14
14
  """
15
15
  import json
16
- from . import config
16
+ from . import config, words
17
17
 
18
18
 
19
19
  KIND = 'setup'
@@ -81,7 +81,7 @@ def prompt(c: dict, server: dict, guide: list, fields: list, secret_label: str,
81
81
  # Nothing to hand the setup to (B10, 2026-10-11): a new install without any AI CLI answered the card's
82
82
  # biggest button with "command not found: claude" - true, and nothing the owner could do with it.
83
83
  NO_AI = ("No AI app is set up on this computer yet, so there is nothing to hand this setup to. Set one up under "
84
- "Connections > AI CLI agents and press this again - or follow the Guide tab and fill the card yourself.")
84
+ f"{words.name('ai_apps')} and press this again - or follow the Guide tab and fill the card yourself.")
85
85
 
86
86
 
87
87
  def runner(store, agent: str = None) -> str:
@@ -91,7 +91,7 @@ def runner(store, agent: str = None) -> str:
91
91
  from . import agents as hub, terminal as term
92
92
  agent = (agent or hub.default_agent(store)).strip()
93
93
  row = store.get_agent(agent)
94
- if not row: raise ValueError(f'no CLI agent named {agent!r} - add one under Connections > AI CLI agents first')
94
+ if not row: raise ValueError(f'no CLI agent named {agent!r} - add one under {words.name("ai_apps")} first')
95
95
  profile = term.with_brain(json.loads(row.get('Config') or '{}'), hub.brain_command(store, agent))
96
96
  try: hub._resolve_cmd(profile.get('cmd') or 'claude')
97
97
  except FileNotFoundError: raise ValueError(NO_AI) from None
@@ -125,7 +125,7 @@ def start(store, server: dict, cid: int, guide: list, fields: list = None, secre
125
125
  except Exception as e:
126
126
  # found is not always runnable (a shim whose target went): the task this press made goes with it
127
127
  if not reused: store.delete_task(tid)
128
- if isinstance(e, OSError): raise ValueError(f"{agent} is set up here but would not start ({e}). Open Connections > AI CLI agents "
128
+ if isinstance(e, OSError): raise ValueError(f"{agent} is set up here but would not start ({e}). Open {words.name('ai_apps')} "
129
129
  "and press Test or Update on it, then press this again.") from None
130
130
  raise
131
131
  t.keep_transcript = False
@@ -17,7 +17,8 @@ class AlchemyError(RuntimeError):
17
17
  def _key(cfg):
18
18
  key = str(cfg.get('api_key') or '').strip()
19
19
  if not key:
20
- raise AlchemyError('no Alchemy API key saved - Connections -> Alchemy')
20
+ from . import words
21
+ raise AlchemyError(f"no Alchemy API key saved - {words.card('Alchemy')}")
21
22
  return key
22
23
 
23
24
 
@@ -291,7 +291,7 @@ def stop_watching(store, t: dict, quiet: bool = False) -> str | None:
291
291
  """A watch at its 30 days ends, and says so with the way back (watch_task again). One with no start of its own -
292
292
  from before watches kept one - ends quietly."""
293
293
  from .store import task_ref
294
- line = None if quiet else f"I've stopped watching for {_who(_waiting_on(store, t))}'s answer on {task_ref(t['TaskId'])} {_title(t)}. Keep going?"
294
+ line = None if quiet else f"I've stopped watching for {_who(_waiting_on(store, t))}'s answer on {task_ref(t['TaskId'])} {_title(t)}. Should I watch for it again?" # "Keep going?" read as the Keep going button
295
295
  if line and not _say(store, t, line, desktop=True): return None
296
296
  store._exec('UPDATE task SET AskedWatch=NULL WHERE TaskId=?', (t['TaskId'],))
297
297
  return line