taskuary 0.3.7.1__tar.gz → 0.3.7.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (566) hide show
  1. {taskuary-0.3.7.1/taskuary.egg-info → taskuary-0.3.7.2}/PKG-INFO +30 -27
  2. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/README.md +29 -26
  3. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/pyproject.toml +1 -1
  4. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/chatformat.py +17 -1
  5. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/concierge.py +3 -1
  6. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/doorway_browse.py +72 -9
  7. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/lookups.py +12 -4
  8. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/remote_assistant.py +53 -9
  9. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/server.py +21 -3
  10. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/settings_schema.json +2 -2
  11. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/store.py +12 -6
  12. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/terminal.py +2 -1
  13. taskuary-0.3.7.1/taskuary/web/assets/AssistantGame-0C4EbdNP.js → taskuary-0.3.7.2/taskuary/web/assets/AssistantGame-BZJj3XwN.js +3 -3
  14. taskuary-0.3.7.1/taskuary/web/assets/GameScene-VFVGUUWW.js → taskuary-0.3.7.2/taskuary/web/assets/GameScene-ATV2SyYO.js +1 -1
  15. taskuary-0.3.7.1/taskuary/web/assets/HubView-C3RE4gI3.js → taskuary-0.3.7.2/taskuary/web/assets/HubView-DtpvsbeL.js +1 -1
  16. taskuary-0.3.7.1/taskuary/web/assets/StudioScene-DbbMffmv.js → taskuary-0.3.7.2/taskuary/web/assets/StudioScene-D4IlNRXi.js +1 -1
  17. taskuary-0.3.7.1/taskuary/web/assets/TasksView-BE0ORh6n.js → taskuary-0.3.7.2/taskuary/web/assets/TasksView-B7m8zBYu.js +1 -1
  18. taskuary-0.3.7.1/taskuary/web/assets/index-BYDpTV3Z.js → taskuary-0.3.7.2/taskuary/web/assets/index-BKrB4ObA.js +14 -14
  19. taskuary-0.3.7.1/taskuary/web/assets/index-DzyUgP3W.css → taskuary-0.3.7.2/taskuary/web/assets/index-DUxLnhhx.css +1 -1
  20. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/index.html +2 -2
  21. {taskuary-0.3.7.1 → taskuary-0.3.7.2/taskuary.egg-info}/PKG-INFO +30 -27
  22. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary.egg-info/SOURCES.txt +8 -7
  23. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_coder_session_continuity.py +16 -0
  24. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_continue_session.py +16 -0
  25. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_morning_line.py +2 -2
  26. taskuary-0.3.7.2/tests/test_phone_browse_pass.py +144 -0
  27. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/LICENSE +0 -0
  28. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/setup.cfg +0 -0
  29. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/__init__.py +0 -0
  30. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/acp.py +0 -0
  31. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/agents.py +0 -0
  32. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/aidefaults.py +0 -0
  33. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/aisetup.py +0 -0
  34. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/alchemy.py +0 -0
  35. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/appfacts.py +0 -0
  36. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/artifacts.py +0 -0
  37. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/assistant.py +0 -0
  38. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/assistantblocks.py +0 -0
  39. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/autoreply.py +0 -0
  40. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/aws.py +0 -0
  41. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/azure.py +0 -0
  42. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/blackboard.py +0 -0
  43. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/brief.py +0 -0
  44. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/browserview.py +0 -0
  45. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/calendar.py +0 -0
  46. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/categories.py +0 -0
  47. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/chains.py +0 -0
  48. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/channels.py +0 -0
  49. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/chatservers.py +0 -0
  50. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/ci.py +0 -0
  51. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/cli.py +0 -0
  52. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/cli_connections.py +0 -0
  53. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/cli_install_terminal.py +0 -0
  54. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/cliinstall.py +0 -0
  55. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/climodels.py +0 -0
  56. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/clipool.py +0 -0
  57. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/clis.py +0 -0
  58. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/clisetup.py +0 -0
  59. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/coder.py +0 -0
  60. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/compose.py +0 -0
  61. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/config.py +0 -0
  62. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/connectorcatalog.json +0 -0
  63. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/connectorcatalog.py +0 -0
  64. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/context.py +0 -0
  65. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/continuity.py +0 -0
  66. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/counsel.py +0 -0
  67. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/databases.py +0 -0
  68. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/db.py +0 -0
  69. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/demo.py +0 -0
  70. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/deps.py +0 -0
  71. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/desktop.py +0 -0
  72. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/devtools.py +0 -0
  73. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/digest.py +0 -0
  74. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/docsync.py +0 -0
  75. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/evalset.py +0 -0
  76. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/evening.py +0 -0
  77. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/files.py +0 -0
  78. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/funnel.py +0 -0
  79. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/funnel_presentation.py +0 -0
  80. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/funnel_selection.py +0 -0
  81. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/general.py +0 -0
  82. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/ghcloseout.py +0 -0
  83. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/github.py +0 -0
  84. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/guard.py +0 -0
  85. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/handbook.py +0 -0
  86. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/handraise.py +0 -0
  87. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/histgen.py +0 -0
  88. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/hooks.py +0 -0
  89. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/hub.py +0 -0
  90. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/images.py +0 -0
  91. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/imapmail.py +0 -0
  92. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/imessage.py +0 -0
  93. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/ingest.py +0 -0
  94. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/intacct.py +0 -0
  95. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/interview.py +0 -0
  96. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/invoice_workflow.py +0 -0
  97. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/jev.py +0 -0
  98. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/knowledge.py +0 -0
  99. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/lanes.json +0 -0
  100. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/learn.py +0 -0
  101. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/learnedgraph.py +0 -0
  102. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/linkedin.py +0 -0
  103. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/live.py +0 -0
  104. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/llm.py +0 -0
  105. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/logs.py +0 -0
  106. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/markets.py +0 -0
  107. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/mcp.py +0 -0
  108. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/messengers.py +0 -0
  109. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/msauth.py +0 -0
  110. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/mssql.py +0 -0
  111. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/operations.py +0 -0
  112. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/outbound.py +0 -0
  113. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/outbox.py +0 -0
  114. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/ownwork.py +0 -0
  115. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/playbooks.py +0 -0
  116. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/pm.py +0 -0
  117. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/policy.py +0 -0
  118. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/problems.py +0 -0
  119. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing.py +0 -0
  120. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_all.py +0 -0
  121. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_inventory.py +0 -0
  122. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_membership.py +0 -0
  123. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_navigation.py +0 -0
  124. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_order.py +0 -0
  125. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_projection.py +0 -0
  126. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_rail.py +0 -0
  127. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_reads.py +0 -0
  128. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_startup.py +0 -0
  129. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/processing_unread.py +0 -0
  130. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/projects.py +0 -0
  131. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/promptmap.py +0 -0
  132. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/proof.py +0 -0
  133. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/proposals.py +0 -0
  134. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/quickbooks.py +0 -0
  135. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/rank.py +0 -0
  136. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/redact.py +0 -0
  137. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/remind.py +0 -0
  138. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/reports.py +0 -0
  139. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/research.py +0 -0
  140. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/reshape.py +0 -0
  141. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/responder.py +0 -0
  142. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/retention.py +0 -0
  143. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/robinhood.py +0 -0
  144. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/routing.py +0 -0
  145. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/routingmemory.py +0 -0
  146. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/scopes.py +0 -0
  147. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/selfclose.py +0 -0
  148. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/semantic.py +0 -0
  149. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/senders.py +0 -0
  150. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/session_artifacts.py +0 -0
  151. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/sessionfiles.py +0 -0
  152. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/settings_defaults.json +0 -0
  153. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/settings_schema.py +0 -0
  154. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/setup.py +0 -0
  155. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/sharepoint.py +0 -0
  156. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/sheets.py +0 -0
  157. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/simplefin.py +0 -0
  158. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/skillimport.py +0 -0
  159. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/skills/soul-interview/SKILL.md +0 -0
  160. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/skills/taskuary-setup/SKILL.md +0 -0
  161. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/social.py +0 -0
  162. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/spawn.py +0 -0
  163. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/taskstate.py +0 -0
  164. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/teller.py +0 -0
  165. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/agent.md +0 -0
  166. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/analyst.md +0 -0
  167. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/coder.md +0 -0
  168. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/coordinator.md +0 -0
  169. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/counsel.md +0 -0
  170. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/digest.md +0 -0
  171. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/history/counsel-0.3.3.5.md +0 -0
  172. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/history/counsel-0.3.6.8.md +0 -0
  173. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/history/counsel-0.3.6.9-examples.md +0 -0
  174. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/history/counsel-0.3.6.9-remind.md +0 -0
  175. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/history/counsel-0.3.6.9.md +0 -0
  176. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/how-it-works.md +0 -0
  177. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/learned.md +0 -0
  178. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/marketer.md +0 -0
  179. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/playbook.md +0 -0
  180. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/profile.md +0 -0
  181. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/researcher.md +0 -0
  182. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/soul.md +0 -0
  183. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/style.md +0 -0
  184. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/trader.md +0 -0
  185. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/templates/triage.md +0 -0
  186. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/testing.py +0 -0
  187. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/toil.py +0 -0
  188. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/toolcatalog.py +0 -0
  189. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/treg.py +0 -0
  190. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/triage.py +0 -0
  191. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/triage_kind_rules.json +0 -0
  192. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/update.py +0 -0
  193. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/verdicts.py +0 -0
  194. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/voice.py +0 -0
  195. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/wabridge.py +0 -0
  196. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/waitroom.py +0 -0
  197. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/walk.py +0 -0
  198. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/assets/RoundedBoxGeometry-BE4rf3sD.js +0 -0
  199. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/favicon.ico +0 -0
  200. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/favicon.png +0 -0
  201. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/assistant.png +0 -0
  202. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/board.png +0 -0
  203. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/connections.png +0 -0
  204. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/docs.png +0 -0
  205. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/hub.png +0 -0
  206. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/reports.png +0 -0
  207. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/settings.png +0 -0
  208. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/web/walk/tasks.png +0 -0
  209. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/webguard.py +0 -0
  210. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/whatsapp/bridge.mjs +0 -0
  211. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/whatsapp/package.json +0 -0
  212. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/whatsapp/policy.mjs +0 -0
  213. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/whatsapp/poll.mjs +0 -0
  214. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/whatsapp/roster.mjs +0 -0
  215. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/whoami.py +0 -0
  216. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/witness.py +0 -0
  217. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/workerstate.py +0 -0
  218. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/workflows.py +0 -0
  219. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary/zoho.py +0 -0
  220. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary.egg-info/dependency_links.txt +0 -0
  221. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary.egg-info/entry_points.txt +0 -0
  222. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary.egg-info/requires.txt +0 -0
  223. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/taskuary.egg-info/top_level.txt +0 -0
  224. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_acp.py +0 -0
  225. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_advisor_idea_words.py +0 -0
  226. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_answer_route.py +0 -0
  227. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_answers_and_reminders.py +0 -0
  228. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_asking.py +0 -0
  229. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_environment.py +0 -0
  230. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_identity.py +0 -0
  231. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_profiles.py +0 -0
  232. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_reply.py +0 -0
  233. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_sentence.py +0 -0
  234. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_source.py +0 -0
  235. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_agent_wall.py +0 -0
  236. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_ai_defaults.py +0 -0
  237. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_aisetup.py +0 -0
  238. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_alchemy.py +0 -0
  239. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_an_inbox_is_not_a_destination.py +0 -0
  240. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_answered_yourself.py +0 -0
  241. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_answers.py +0 -0
  242. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_api.py +0 -0
  243. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_api_worker_signals.py +0 -0
  244. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_app_uptime.py +0 -0
  245. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_appfacts.py +0 -0
  246. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_approval_interrupt.py +0 -0
  247. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant.py +0 -0
  248. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_acts.py +0 -0
  249. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_blocks.py +0 -0
  250. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_can_look_things_up.py +0 -0
  251. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_doorways.py +0 -0
  252. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_ideas.py +0 -0
  253. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_notifications.py +0 -0
  254. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_presentation.py +0 -0
  255. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_reactions.py +0 -0
  256. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_assistant_verdicts.py +0 -0
  257. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_async_triage.py +0 -0
  258. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_audit_chain.py +0 -0
  259. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_audit_fixes.py +0 -0
  260. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_auto_start.py +0 -0
  261. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_autoreply.py +0 -0
  262. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_aws_region.py +0 -0
  263. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_azure_discovery.py +0 -0
  264. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_banner_is_one_rule.py +0 -0
  265. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_blackboard.py +0 -0
  266. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_brain_layer.py +0 -0
  267. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_brain_reaches_the_session.py +0 -0
  268. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_browser_session.py +0 -0
  269. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_browser_workflow.py +0 -0
  270. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_browserview.py +0 -0
  271. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_button_promises.py +0 -0
  272. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_calendar.py +0 -0
  273. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_calendar_today.py +0 -0
  274. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_canvas_relay.py +0 -0
  275. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_canvas_sections.py +0 -0
  276. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_card_story_phone.py +0 -0
  277. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_categories.py +0 -0
  278. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cc.py +0 -0
  279. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cc_triage.py +0 -0
  280. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_doors.py +0 -0
  281. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_echo_mail.py +0 -0
  282. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_freshness.py +0 -0
  283. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_is_not_one_task.py +0 -0
  284. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_proposals.py +0 -0
  285. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_queue.py +0 -0
  286. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_relationship.py +0 -0
  287. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_retention.py +0 -0
  288. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chat_setup.py +0 -0
  289. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chatformat.py +0 -0
  290. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chatservers.py +0 -0
  291. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_chinese_clis.py +0 -0
  292. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_clean_context.py +0 -0
  293. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_connections.py +0 -0
  294. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_failure.py +0 -0
  295. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_help.py +0 -0
  296. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_install.py +0 -0
  297. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_install_terminal.py +0 -0
  298. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_on_fresh_path.py +0 -0
  299. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_setup.py +0 -0
  300. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cli_update.py +0 -0
  301. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_climodels.py +0 -0
  302. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_clipool.py +0 -0
  303. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_clis.py +0 -0
  304. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_closeout.py +0 -0
  305. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cloud.py +0 -0
  306. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cloud_sources.py +0 -0
  307. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_completion_freshness.py +0 -0
  308. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_compose.py +0 -0
  309. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_compose_sources.py +0 -0
  310. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_compose_workflows.py +0 -0
  311. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_concierge.py +0 -0
  312. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_concierge_counsel.py +0 -0
  313. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_config.py +0 -0
  314. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_context.py +0 -0
  315. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_context_refresh_freshness.py +0 -0
  316. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_coordination.py +0 -0
  317. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_core.py +0 -0
  318. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_correction_doors.py +0 -0
  319. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_counsel.py +0 -0
  320. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_counsel_consumers.py +0 -0
  321. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_counsel_migration.py +0 -0
  322. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_counsel_sections.py +0 -0
  323. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_current_restore.py +0 -0
  324. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_cwlogs_paging.py +0 -0
  325. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_databases.py +0 -0
  326. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_demo.py +0 -0
  327. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_deps.py +0 -0
  328. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_desktop.py +0 -0
  329. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_devin.py +0 -0
  330. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_devtools.py +0 -0
  331. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_diff_review.py +0 -0
  332. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_digest_brief.py +0 -0
  333. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_dispatch_retries.py +0 -0
  334. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_docs_and_llm.py +0 -0
  335. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_docs_flow.py +0 -0
  336. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_duplicate_connectors.py +0 -0
  337. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_email_chains.py +0 -0
  338. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_email_identity_routing.py +0 -0
  339. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_ending_a_run_writes_the_answer.py +0 -0
  340. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_evening_brief.py +0 -0
  341. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_every_card_is_reachable.py +0 -0
  342. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_every_cli_startable.py +0 -0
  343. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_explicit_completion.py +0 -0
  344. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_factory.py +0 -0
  345. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_failed_acts.py +0 -0
  346. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_feed_working.py +0 -0
  347. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_files.py +0 -0
  348. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_final_answer_capture.py +0 -0
  349. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_finished_chat_stays_finished.py +0 -0
  350. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_floating_assistant.py +0 -0
  351. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_follow_up_verdict.py +0 -0
  352. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_fresh_evaluation.py +0 -0
  353. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_freshness.py +0 -0
  354. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_freshness_walk.py +0 -0
  355. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_funnel.py +0 -0
  356. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_general.py +0 -0
  357. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_github_auto.py +0 -0
  358. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_github_images.py +0 -0
  359. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_guard.py +0 -0
  360. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_handbook.py +0 -0
  361. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_handbook_topics.py +0 -0
  362. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_handoff_channels.py +0 -0
  363. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_handraise.py +0 -0
  364. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_harvest.py +0 -0
  365. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_histgen.py +0 -0
  366. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_home_is_never_yours.py +0 -0
  367. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_hooks_events.py +0 -0
  368. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_hooks_version.py +0 -0
  369. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_ideas_triage.py +0 -0
  370. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_ignore_sender.py +0 -0
  371. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_ignore_sender_quiets_its_work.py +0 -0
  372. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_images.py +0 -0
  373. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_imap_catchup.py +0 -0
  374. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_imap_history.py +0 -0
  375. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_imapmail.py +0 -0
  376. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_imessage.py +0 -0
  377. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_inline_pictures.py +0 -0
  378. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_intacct.py +0 -0
  379. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_interrupted_work.py +0 -0
  380. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_invite_is_not_work.py +0 -0
  381. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_invoice_workflow.py +0 -0
  382. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_jev.py +0 -0
  383. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_judge_reads_the_conclusion.py +0 -0
  384. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_kind_dispatch.py +0 -0
  385. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_knowledge.py +0 -0
  386. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_lane_vocabulary.py +0 -0
  387. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_learnedgraph.py +0 -0
  388. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_lifecycle.py +0 -0
  389. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_lifespan_loops_are_guarded.py +0 -0
  390. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_linkedin.py +0 -0
  391. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_linkedin_signin.py +0 -0
  392. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_live.py +0 -0
  393. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_local_file.py +0 -0
  394. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_lookups.py +0 -0
  395. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_mail_catchup.py +0 -0
  396. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_mail_fetch_cost.py +0 -0
  397. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_mail_folders.py +0 -0
  398. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_mark_read.py +0 -0
  399. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_markets.py +0 -0
  400. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_mcp.py +0 -0
  401. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_meeting_prep.py +0 -0
  402. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_message_thread.py +0 -0
  403. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_messengers.py +0 -0
  404. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_msauth.py +0 -0
  405. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_mssql.py +0 -0
  406. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_multi_question.py +0 -0
  407. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_muse.py +0 -0
  408. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_no_pydantic_v1.py +0 -0
  409. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_noop_ending.py +0 -0
  410. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_not_coding.py +0 -0
  411. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_note_retrieval.py +0 -0
  412. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_onboarding_walk.py +0 -0
  413. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_one_app_one_reason.py +0 -0
  414. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_one_pty_one_geometry.py +0 -0
  415. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_only_your_own_thread.py +0 -0
  416. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_openai_compatible_brains.py +0 -0
  417. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_operations.py +0 -0
  418. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_outbound_reports.py +0 -0
  419. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_outbox.py +0 -0
  420. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_own_rows_no_reply.py +0 -0
  421. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_person_name.py +0 -0
  422. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_phone_picks.py +0 -0
  423. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_phone_walk_ux.py +0 -0
  424. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_playbook_setup.py +0 -0
  425. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_playbooks.py +0 -0
  426. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_pm.py +0 -0
  427. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_poll_lanes.py +0 -0
  428. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_poll_overlap.py +0 -0
  429. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_poll_parallel.py +0 -0
  430. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_poll_sources.py +0 -0
  431. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_pr_comments.py +0 -0
  432. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_problems.py +0 -0
  433. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_problems_dismiss.py +0 -0
  434. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_procedure_selection.py +0 -0
  435. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_processing_demo_replay.py +0 -0
  436. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_processing_ledger.py +0 -0
  437. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_profile_is_a_role.py +0 -0
  438. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_projects.py +0 -0
  439. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_prompt_images.py +0 -0
  440. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_prompt_sources.py +0 -0
  441. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_promptmap_and_catalog.py +0 -0
  442. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_proof_ci_proposals.py +0 -0
  443. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_pypi_downloads.py +0 -0
  444. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_quickbooks.py +0 -0
  445. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_qwen.py +0 -0
  446. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_rail_decisions.py +0 -0
  447. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_rank.py +0 -0
  448. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_rate_limit.py +0 -0
  449. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_read_text.py +0 -0
  450. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_recent_closures.py +0 -0
  451. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reclassify.py +0 -0
  452. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_redact.py +0 -0
  453. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_redact_doors.py +0 -0
  454. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_remind.py +0 -0
  455. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_remote_assistant.py +0 -0
  456. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_remote_sections.py +0 -0
  457. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reply_always_drafts.py +0 -0
  458. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reply_attachments.py +0 -0
  459. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reply_channels.py +0 -0
  460. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reply_envelope.py +0 -0
  461. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reply_needs_a_correspondent.py +0 -0
  462. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reply_sources.py +0 -0
  463. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reply_voice.py +0 -0
  464. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_repo_choice_triage.py +0 -0
  465. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_alerts.py +0 -0
  466. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_deliver.py +0 -0
  467. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_headline.py +0 -0
  468. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_one_road.py +0 -0
  469. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_order_and_research.py +0 -0
  470. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_prompt_isolation.py +0 -0
  471. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_refusal.py +0 -0
  472. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_routing.py +0 -0
  473. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_report_triage.py +0 -0
  474. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_research.py +0 -0
  475. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_research_more.py +0 -0
  476. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_review_task.py +0 -0
  477. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_reviews.py +0 -0
  478. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_robinhood.py +0 -0
  479. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_routing_memory.py +0 -0
  480. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_s3_poll_paging.py +0 -0
  481. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_scopes.py +0 -0
  482. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_seed_fits_a_tty.py +0 -0
  483. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_seeded_reports.py +0 -0
  484. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_selector_vocabulary.py +0 -0
  485. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_semantic.py +0 -0
  486. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_send_outcomes.py +0 -0
  487. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_send_targets.py +0 -0
  488. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_sender_trust.py +0 -0
  489. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_sender_words.py +0 -0
  490. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_session_artifacts.py +0 -0
  491. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_session_continuity.py +0 -0
  492. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_session_endings.py +0 -0
  493. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_session_files.py +0 -0
  494. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_settings_defaults_json.py +0 -0
  495. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_settings_schema.py +0 -0
  496. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_setup.py +0 -0
  497. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_setup_skill.py +0 -0
  498. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_setup_walk.py +0 -0
  499. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_sheets_sharepoint.py +0 -0
  500. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_simplefin.py +0 -0
  501. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_skillimport.py +0 -0
  502. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_social.py +0 -0
  503. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_someone_else_replied.py +0 -0
  504. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_soul_interview.py +0 -0
  505. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_startup_contract.py +0 -0
  506. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_stay_open.py +0 -0
  507. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_stay_open_doors.py +0 -0
  508. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_store_app_cli.py +0 -0
  509. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_store_hotpaths.py +0 -0
  510. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_store_pokes.py +0 -0
  511. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_sync_clock.py +0 -0
  512. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_task_ask.py +0 -0
  513. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_task_checklist.py +0 -0
  514. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_task_controls_operations.py +0 -0
  515. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_task_identity.py +0 -0
  516. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_task_refs.py +0 -0
  517. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_task_tools.py +0 -0
  518. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_taskstate.py +0 -0
  519. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_telegram_buttons.py +0 -0
  520. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_teller.py +0 -0
  521. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_terminal.py +0 -0
  522. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_the_exe_ships_what_the_wheel_ships.py +0 -0
  523. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_the_split_holds.py +0 -0
  524. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_toil.py +0 -0
  525. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_tracker_revisions.py +0 -0
  526. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_treg.py +0 -0
  527. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_cleanup.py +0 -0
  528. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_dataset.py +0 -0
  529. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_errors.py +0 -0
  530. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_images.py +0 -0
  531. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_joins.py +0 -0
  532. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_pr_rule.py +0 -0
  533. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_retry_sweep.py +0 -0
  534. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_triage_urgent.py +0 -0
  535. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_update.py +0 -0
  536. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_update_refused.py +0 -0
  537. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_urgent_and_handoff.py +0 -0
  538. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_verdict_paths.py +0 -0
  539. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_verdict_shape.py +0 -0
  540. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_verdict_sticks.py +0 -0
  541. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_vision.py +0 -0
  542. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_voice.py +0 -0
  543. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_wabridge.py +0 -0
  544. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_wabridge_log_trim.py +0 -0
  545. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_waitroom.py +0 -0
  546. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_walk_order.py +0 -0
  547. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_watermark.py +0 -0
  548. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_web_entrypoint.py +0 -0
  549. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_webguard.py +0 -0
  550. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_whatsapp_documents.py +0 -0
  551. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_whatsapp_images.py +0 -0
  552. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_whoami.py +0 -0
  553. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_why_not_started.py +0 -0
  554. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_withdrawn.py +0 -0
  555. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_witness.py +0 -0
  556. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_worker_brief.py +0 -0
  557. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_worker_events.py +0 -0
  558. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_worker_resumes.py +0 -0
  559. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_worker_scenarios.py +0 -0
  560. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_worker_surfaces.py +0 -0
  561. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_workerstate_said.py +0 -0
  562. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_workflows.py +0 -0
  563. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_zz_chipverbs.py +0 -0
  564. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_zz_lastword.py +0 -0
  565. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_zz_setupchat.py +0 -0
  566. {taskuary-0.3.7.1 → taskuary-0.3.7.2}/tests/test_zz_toolcatalog.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskuary
3
- Version: 0.3.7.1
3
+ Version: 0.3.7.2
4
4
  Summary: Automate your job - the local-first operating system for your work: AI triage in, coding agents out.
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/ldbumble/taskuary
@@ -69,7 +69,7 @@ Dynamic: license-file
69
69
 
70
70
  [![CI](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml/badge.svg)](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml)
71
71
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/ldbumble/taskuary/badge)](https://scorecard.dev/viewer/?uri=github.com/ldbumble/taskuary)
72
- [![PyPI](https://img.shields.io/pypi/v/taskuary.svg?cacheSeconds=300&release=0.3.7.1&asof=2026-09-28T1810)](https://pypi.org/project/taskuary/)
72
+ [![PyPI](https://img.shields.io/pypi/v/taskuary.svg?cacheSeconds=300&release=0.3.7.2&asof=2026-09-28T1810)](https://pypi.org/project/taskuary/)
73
73
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776ab.svg)](https://github.com/ldbumble/taskuary)
74
74
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
75
75
  [![Stars](https://img.shields.io/github/stars/ldbumble/taskuary?style=flat&color=d4a72c&label=%E2%98%85%20stars)](https://github.com/ldbumble/taskuary/stargazers)
@@ -83,7 +83,7 @@ your agents, and brings decisions back to you. Nothing sends or ships without yo
83
83
 
84
84
  ![The Taskuary Studio assembling as work arrives and AI agents take their seats.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/hero.gif?v=workspace)
85
85
 
86
- Taskuary is early—currently **v0.3.7.1**—so breaking changes are still possible before 1.0.
86
+ Taskuary is early—currently **v0.3.7.2**—so breaking changes are still possible before 1.0.
87
87
 
88
88
  <p align="center">
89
89
  <a href="https://taskuary.com/demo/"><img
@@ -100,47 +100,50 @@ Taskuary is early—currently **v0.3.7.1**—so breaking changes are still possi
100
100
  One request, from arrival to your approval. Follow Ruth's request for the latest vendor spend
101
101
  numbers through the real app, using fictional demo data.
102
102
 
103
- ### 1. Connect every system. Keep control.
103
+ ### 1. Everything lands in one place
104
104
 
105
- Mail, chats, issue trackers, alerts, and reports land on one Timeline. See what arrived,
106
- what became a task, and what needs you without opening every system in turn.
105
+ Mail, chats, issue trackers, alerts, and reports arrive on one rail, sorted by what they need:
106
+ **Urgent**, **On you**, **For later**, the Advisor's ideas, and **FYI**. Beside it, the Assistant
107
+ says what came in and who is waiting, so you never open each system in turn.
107
108
 
108
- ![An annotated Timeline: each item shows its original time below its source—Email, Teams, WhatsApp, GitHub, SQL report, Assistant, Daily digest, or Calendar.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/01-timeline-sources-and-times.png)
109
+ ![The work rail sorting today's items into Urgent, On you, Advisor ideas, and FYI, beside the Assistant's morning summary of who is waiting.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/01-timeline-sources-and-times.png?v=95295dd)
109
110
 
110
- ### 2. Turn incoming work into tasks
111
+ ### 2. Let the Assistant walk you through it
111
112
 
112
- Ruth asks for the August total, the change from July, and a breakdown by category.
113
- Taskuary creates a task with the original request and assigns it to an agent.
113
+ Choose **Walk me through my tasks**. The Assistant puts one item on the table at a time, as the
114
+ same task card you would open yourself, with the next actions under it: **Next**, **Write reply**,
115
+ **Start an agent**. The buttons always do the same thing; the chat line is for everything else,
116
+ and the Assistant already has the message, the thread, and your past decisions to answer from.
114
117
 
115
- ![Ruth's request becomes TQ-0018, with its instructions, owner, and agent work together on the task page.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/02-task.png)
118
+ ![The Assistant bringing Ruth's request into the chat as task TQ-0018, with Next, Write reply, and Start an agent under it.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/05-assistant.png?v=95295dd)
116
119
 
117
- ### 3. Watch the agent work
120
+ ### 3. Every request becomes a task with its whole story
118
121
 
119
- Open the task to follow the analysis. Here, the general agent prepares the numbers,
120
- checks that the categories add up, and drafts a reply.
122
+ Open any item to see how it got here: the message, what triage decided and why, which agent
123
+ has it, and where the reply stands.
121
124
 
122
- ![The general agent's completed vendor spend analysis, with category totals, comparison, and source.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/03-agent.png)
125
+ ![Ruth's request on its task: the message, the triage decision, the agent, and the reply still to write.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/02-task.png?v=95295dd)
123
126
 
124
- ### 4. Approve the outcome
127
+ ### 4. The agent works inside the chat
125
128
 
126
- The reply waits in **Review**, beside the request that started it. Read it, edit it,
127
- and choose **Approve & send** when it is ready.
129
+ **Start an agent** and it works in the same card. Here the analyst prepares the numbers, checks
130
+ that the categories add up, names its source, and drafts the reply. Nothing is sent.
128
131
 
129
- ![Review shows Ruth's original request and the prepared reply, with Approve & send waiting for the owner.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/04-review.png)
132
+ ![The analyst's finished vendor spend analysis inside the chat, with category totals, the change from July, and its source.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/03-agent.png?v=95295dd)
130
133
 
131
- ### 5. Let the Assistant walk you through it
134
+ ### 5. The last word is yours
132
135
 
133
- Choose **Walk me through my tasks**. The Assistant brings one item into the conversation,
134
- explains what needs your attention, and puts the next action within reach.
136
+ The prepared reply waits on the task, beside the request that started it. Read it, edit it,
137
+ and choose **Approve & send** when it is ready.
135
138
 
136
- ![A close-up of the Assistant bringing Ruth's request into the conversation, with a link to its task.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/05-assistant.png)
139
+ ![The drafted reply to Ruth waiting on its task, with Approve & send, Reject, and Regenerate with AI.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/04-review.png?v=95295dd)
137
140
 
138
- ### 6. Start your day with the daily digest
141
+ ### 6. Start your day before it gets busy
139
142
 
140
- Open your morning brief to see what people need, what is in flight, and what is on your calendar.
141
- The day's meetings sit above the digest, so Ruth's request has a clear deadline: the operations review.
143
+ Each morning the Assistant opens with today's meetings on a timeline and who needs a word from you.
144
+ Ruth's request has a clear deadline: the 11:30 operations review.
142
145
 
143
- ![An animated close-up of the morning digest and calendar, showing the operations review and vendor planning meeting.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/06-morning.gif)
146
+ ![An animated close-up of the morning: today's meetings on a timeline, then the people and agents waiting.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/06-morning.gif?v=95295dd)
144
147
 
145
148
  ## Key features
146
149
 
@@ -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.7.1&asof=2026-09-28T1810)](https://pypi.org/project/taskuary/)
7
+ [![PyPI](https://img.shields.io/pypi/v/taskuary.svg?cacheSeconds=300&release=0.3.7.2&asof=2026-09-28T1810)](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)
@@ -18,7 +18,7 @@ your agents, and brings decisions back to you. Nothing sends or ships without yo
18
18
 
19
19
  ![The Taskuary Studio assembling as work arrives and AI agents take their seats.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/hero.gif?v=workspace)
20
20
 
21
- Taskuary is early—currently **v0.3.7.1**—so breaking changes are still possible before 1.0.
21
+ Taskuary is early—currently **v0.3.7.2**—so breaking changes are still possible before 1.0.
22
22
 
23
23
  <p align="center">
24
24
  <a href="https://taskuary.com/demo/"><img
@@ -35,47 +35,50 @@ Taskuary is early—currently **v0.3.7.1**—so breaking changes are still possi
35
35
  One request, from arrival to your approval. Follow Ruth's request for the latest vendor spend
36
36
  numbers through the real app, using fictional demo data.
37
37
 
38
- ### 1. Connect every system. Keep control.
38
+ ### 1. Everything lands in one place
39
39
 
40
- Mail, chats, issue trackers, alerts, and reports land on one Timeline. See what arrived,
41
- what became a task, and what needs you without opening every system in turn.
40
+ Mail, chats, issue trackers, alerts, and reports arrive on one rail, sorted by what they need:
41
+ **Urgent**, **On you**, **For later**, the Advisor's ideas, and **FYI**. Beside it, the Assistant
42
+ says what came in and who is waiting, so you never open each system in turn.
42
43
 
43
- ![An annotated Timeline: each item shows its original time below its source—Email, Teams, WhatsApp, GitHub, SQL report, Assistant, Daily digest, or Calendar.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/01-timeline-sources-and-times.png)
44
+ ![The work rail sorting today's items into Urgent, On you, Advisor ideas, and FYI, beside the Assistant's morning summary of who is waiting.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/01-timeline-sources-and-times.png?v=95295dd)
44
45
 
45
- ### 2. Turn incoming work into tasks
46
+ ### 2. Let the Assistant walk you through it
46
47
 
47
- Ruth asks for the August total, the change from July, and a breakdown by category.
48
- Taskuary creates a task with the original request and assigns it to an agent.
48
+ Choose **Walk me through my tasks**. The Assistant puts one item on the table at a time, as the
49
+ same task card you would open yourself, with the next actions under it: **Next**, **Write reply**,
50
+ **Start an agent**. The buttons always do the same thing; the chat line is for everything else,
51
+ and the Assistant already has the message, the thread, and your past decisions to answer from.
49
52
 
50
- ![Ruth's request becomes TQ-0018, with its instructions, owner, and agent work together on the task page.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/02-task.png)
53
+ ![The Assistant bringing Ruth's request into the chat as task TQ-0018, with Next, Write reply, and Start an agent under it.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/05-assistant.png?v=95295dd)
51
54
 
52
- ### 3. Watch the agent work
55
+ ### 3. Every request becomes a task with its whole story
53
56
 
54
- Open the task to follow the analysis. Here, the general agent prepares the numbers,
55
- checks that the categories add up, and drafts a reply.
57
+ Open any item to see how it got here: the message, what triage decided and why, which agent
58
+ has it, and where the reply stands.
56
59
 
57
- ![The general agent's completed vendor spend analysis, with category totals, comparison, and source.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/03-agent.png)
60
+ ![Ruth's request on its task: the message, the triage decision, the agent, and the reply still to write.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/02-task.png?v=95295dd)
58
61
 
59
- ### 4. Approve the outcome
62
+ ### 4. The agent works inside the chat
60
63
 
61
- The reply waits in **Review**, beside the request that started it. Read it, edit it,
62
- and choose **Approve & send** when it is ready.
64
+ **Start an agent** and it works in the same card. Here the analyst prepares the numbers, checks
65
+ that the categories add up, names its source, and drafts the reply. Nothing is sent.
63
66
 
64
- ![Review shows Ruth's original request and the prepared reply, with Approve & send waiting for the owner.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/04-review.png)
67
+ ![The analyst's finished vendor spend analysis inside the chat, with category totals, the change from July, and its source.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/03-agent.png?v=95295dd)
65
68
 
66
- ### 5. Let the Assistant walk you through it
69
+ ### 5. The last word is yours
67
70
 
68
- Choose **Walk me through my tasks**. The Assistant brings one item into the conversation,
69
- explains what needs your attention, and puts the next action within reach.
71
+ The prepared reply waits on the task, beside the request that started it. Read it, edit it,
72
+ and choose **Approve & send** when it is ready.
70
73
 
71
- ![A close-up of the Assistant bringing Ruth's request into the conversation, with a link to its task.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/05-assistant.png)
74
+ ![The drafted reply to Ruth waiting on its task, with Approve & send, Reject, and Regenerate with AI.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/04-review.png?v=95295dd)
72
75
 
73
- ### 6. Start your day with the daily digest
76
+ ### 6. Start your day before it gets busy
74
77
 
75
- Open your morning brief to see what people need, what is in flight, and what is on your calendar.
76
- The day's meetings sit above the digest, so Ruth's request has a clear deadline: the operations review.
78
+ Each morning the Assistant opens with today's meetings on a timeline and who needs a word from you.
79
+ Ruth's request has a clear deadline: the 11:30 operations review.
77
80
 
78
- ![An animated close-up of the morning digest and calendar, showing the operations review and vendor planning meeting.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/06-morning.gif)
81
+ ![An animated close-up of the morning: today's meetings on a timeline, then the people and agents waiting.](https://raw.githubusercontent.com/ldbumble/taskuary/master/docs/readme/06-morning.gif?v=95295dd)
79
82
 
80
83
  ## Key features
81
84
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "taskuary"
7
- version = "0.3.7.1"
7
+ version = "0.3.7.2"
8
8
  description = "Automate your job - the local-first operating system for your work: AI triage in, coding agents out."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -188,6 +188,22 @@ def split(text: str, limit: int = HARD) -> list:
188
188
  return out
189
189
 
190
190
 
191
+ def json_rows(text: str) -> str:
192
+ """Rows that arrived as one JSON object per line - a report whose summary never came, the demo's - as a markdown table,
193
+ so the door lays them out like any other table ({"site": "Lakeview", "headcount": 112} went to the phone as that, braces
194
+ and quotes, 2026-09-30 phone test). Anything that is not ALL flat objects is left exactly as it was."""
195
+ import json
196
+ lines = [l.strip() for l in str(text or '').splitlines() if l.strip()]
197
+ if len(lines) < 2: return text
198
+ try: rows = [json.loads(l) for l in lines]
199
+ except ValueError: return text
200
+ if not all(isinstance(r, dict) and r and all(not isinstance(v, (dict, list)) for v in r.values()) for r in rows): return text
201
+ cols = list(dict.fromkeys(k for r in rows for k in r))
202
+ cell = lambda v: '' if v is None else str(v).replace('|', '/')
203
+ return '\n'.join(['| ' + ' | '.join(cols) + ' |', '|' + '---|' * len(cols)]
204
+ + ['| ' + ' | '.join(cell(r.get(c)) for c in cols) + ' |' for r in rows])
205
+
206
+
191
207
  def blocks(body, limit: int = HARD) -> list:
192
208
  """A report as the messages a chat should receive: one per section, in order.
193
209
 
@@ -200,7 +216,7 @@ def blocks(body, limit: int = HARD) -> list:
200
216
  out = []
201
217
  for title, text in sections(strip_raw(body)):
202
218
  head = f'## {title}' if title else ''
203
- text = text.strip()
219
+ text = json_rows(text.strip()).strip()
204
220
  if not text: continue
205
221
  for piece in split(text, max(200, limit - len(head) - 2)):
206
222
  out.append(f'{head}\n{piece}'.strip() if head else piece)
@@ -1879,7 +1879,9 @@ def surface(store, key: str = None, llm=None, actor: str = 'owner', only: str =
1879
1879
  f"I'll bring {'it' if n == 1 else 'them'} round again in a while - or open {'it' if n == 1 else 'one'} now.")
1880
1880
  # ...and the way to them NOW, by name: a Next under this line only said it again (2026-09-23, six days running).
1881
1881
  # What waits on the owner first - a close-out, an agent's question - then the rest.
1882
- opens = [{'verb': 'open', 'key': i['key'], 'label': f"Open {i.get('ref') or _title_cut(i.get('title') or 'it', 40)}"}
1882
+ # ...each saying WHAT it is, not a bare number (the owner, 2026-09-30: "have to write what they are about a little")
1883
+ opens = [{'verb': 'open', 'key': i['key'], 'label': ' · '.join(x for x in (
1884
+ f"Open {i.get('ref') or ''}".strip(), _title_cut(' '.join(str(i.get('title') or 'it').split()), 50)) if x)}
1883
1885
  for i in sorted(waiting, key=lambda i: not funnel.on_you(i))[:3]]
1884
1886
  elif only and left:
1885
1887
  # the filtered set is done; what remains is the rest of the pipe - offer it rather than call the day over
@@ -62,14 +62,31 @@ def _connected(store) -> dict:
62
62
  return out
63
63
 
64
64
 
65
- def browse(store, area: str, section: str = None, open_: str = None) -> tuple[str, list]:
65
+ POLL_MAX, PAGE = 12, 10 # WhatsApp's poll holds twelve (whatsapp/poll.mjs cuts the rest SILENTLY); a page leaves room
66
+
67
+
68
+ def paged(rows: list, up: list, act: dict, page: int = 0) -> list:
69
+ """The picks for one page: ten rows, More when there are more, then the way back - never past twelve. The Connections
70
+ menu offered seventeen and a list of cards twelve plus Back, so the last five sections and Back could not be tapped
71
+ (2026-09-30 phone test)."""
72
+ if len(rows) + len(up) <= POLL_MAX: return rows + up
73
+ page = max(0, int(page or 0))
74
+ here = rows[page * PAGE:(page + 1) * PAGE]
75
+ more = [(f'More ({len(rows) - (page + 1) * PAGE} left)', {**act, 'page': page + 1})] if (page + 1) * PAGE < len(rows) else \
76
+ [('From the top', {**act, 'page': 0})]
77
+ return here + more + up[:POLL_MAX - len(here) - 1]
78
+
79
+
80
+ def browse(store, area: str, section: str = None, open_: str = None, page: int = 0) -> tuple[str, list]:
66
81
  """(what to say, the picks under it) for one browse step. Back is always a pick; so is the way up."""
67
- if area == 'connections': return _connections(store, section, open_)
68
- if area == 'settings': return _settings(store, section, open_)
82
+ if area == 'connections': return _connections(store, section, open_, page)
83
+ if area == 'settings': return _settings(store, section, open_, page)
84
+ if area == 'reports': return _reports(store, open_, page)
85
+ if area == 'hub': return _hub(store, open_, page)
69
86
  return f'I cannot browse {area} here yet - it is on the desktop.', []
70
87
 
71
88
 
72
- def _connections(store, section, open_):
89
+ def _connections(store, section, open_, page=0):
73
90
  from . import connectorcatalog
74
91
  cards = [c for c in connectorcatalog.cards() if c.get('group')]
75
92
  state = _connected(store)
@@ -87,18 +104,62 @@ def _connections(store, section, open_):
87
104
  rows = [c for c in cards if c['group'] == section]
88
105
  lines = [f"· {c['title']} - {state.get(c['type']) or ('planned' if c.get('planned') else 'not connected')}" for c in rows]
89
106
  picks = [(c['title'], {'t': 'browse', 'area': 'connections', 'section': section, 'open': c['type']}) for c in rows if not c.get('planned')]
90
- return f"CONNECTIONS · {section.upper()} · {len(rows)}\n" + '\n'.join(lines), picks[:12] + up
107
+ return (f"CONNECTIONS · {section.upper()} · {len(rows)}\n" + '\n'.join(lines),
108
+ paged(picks, up, {'t': 'browse', 'area': 'connections', 'section': section}, page))
91
109
  on = sum(1 for v in state.values() if v == 'connected')
92
110
  lines = [f"{g} · {sum(1 for c in cards if c['group'] == g)}" for g in groups]
93
111
  return (f'Connections - {on} connected. Pick a section:\n' + '\n'.join(f'· {x}' for x in lines),
94
- [(g, {'t': 'browse', 'area': 'connections', 'section': g}) for g in groups])
112
+ paged([(g, {'t': 'browse', 'area': 'connections', 'section': g}) for g in groups], [], {'t': 'browse', 'area': 'connections'}, page))
113
+
114
+
115
+ def _reports(store, open_, page=0):
116
+ """REPORTS, the desktop sidebar's list as picks (the owner, 2026-09-30): each one's clock and how its last run went, then
117
+ one opened - what it is, where it goes, what the last run said. Running or changing one is words: the model proposes it."""
118
+ from . import appfacts
119
+ rows = appfacts.reports(store)
120
+ up = [('Back to Reports', {'t': 'browse', 'area': 'reports'})]
121
+ def last(r): return 'never ran' if r['last_ok'] is None else 'last run FAILED' if r['last_ok'] is False else f"ran {r['last_at'][:16]}"
122
+ if open_:
123
+ r = next((x for x in rows if str(x['source_id']) == str(open_)), None)
124
+ if not r: return 'That report is not there any more.', up
125
+ said = str(r['last_said'] or '').strip()
126
+ text = (f"{'WORKFLOW' if r['workflow'] else 'REPORT'} · {r['title']}{'' if r['active'] else ' (off)'}\n"
127
+ f"When: {r['schedule'] or 'no clock - it runs when asked'}\nReaches you: {r['reach']}\nGoes: {r['goes']}\n{last(r).capitalize()}"
128
+ + (f"\n> {said}" if said else '')
129
+ + '\n\nSay "run it now", or what to change, and I propose it for your yes.')
130
+ return text, up
131
+ if not rows: return 'No reports or workflows are set up yet. Say "set up a report" and I walk you through one.', []
132
+ lines = [f"· {r['title']}{'' if r['active'] else ' (off)'} - {r['schedule'] or 'no clock'}; {last(r)}" for r in rows]
133
+ return (f'REPORTS · {len(rows)}\n' + '\n'.join(lines),
134
+ paged([(r['title'], {'t': 'browse', 'area': 'reports', 'open': r['source_id']}) for r in rows], [], {'t': 'browse', 'area': 'reports'}, page))
135
+
136
+
137
+ def _hub(store, open_, page=0):
138
+ """THE HUB, newest first as the desktop lists it (the owner, 2026-09-30): what the agents worked out, each one openable."""
139
+ up = [('Back to the Hub', {'t': 'browse', 'area': 'hub'})]
140
+ if open_:
141
+ e = store.lore_get(int(open_))
142
+ if not e: return 'That entry is not on the Hub any more.', up
143
+ body = str(e.get('Body') or '').strip()
144
+ text = (f"HUB · {e.get('Topic') or 'general'}\n*{e.get('Title') or ''}*\n"
145
+ f"by {e.get('Author') or 'an agent'} · score {e.get('Score') or 0} · {len(store.lore_comments(int(open_)) or [])} comments\n\n"
146
+ + (body[:1500] + ('…' if len(body) > 1500 else '')))
147
+ return text, up
148
+ posts = store.lore_posts(None, None, 40, 'new', 'live', None)
149
+ if not posts: return 'Nothing on the Hub yet - agents post what they work out as they go.', []
150
+ lines = [f"· {p.get('Title') or ''} ({p.get('Topic') or 'general'}, {p.get('Score') or 0})" for p in posts[:20]]
151
+ n = store.lore_count()
152
+ n = n.get('posts', len(posts)) if isinstance(n, dict) else n
153
+ return (f"HUB · {n} entries, newest first\n" + '\n'.join(lines),
154
+ paged([((p.get('Title') or '')[:90], {'t': 'browse', 'area': 'hub', 'open': p['LoreId']}) for p in posts[:20]], [],
155
+ {'t': 'browse', 'area': 'hub'}, page))
95
156
 
96
157
 
97
158
  def _schema() -> dict:
98
159
  return json.loads((Path(__file__).with_name('settings_schema.json')).read_text(encoding='utf-8'))
99
160
 
100
161
 
101
- def _settings(store, section, open_):
162
+ def _settings(store, section, open_, page=0):
102
163
  schema, st = _schema(), store.get_settings()
103
164
  knobs = schema.get('knobs') or {}
104
165
  up = [('Back to Settings', {'t': 'browse', 'area': 'settings'})]
@@ -106,6 +167,7 @@ def _settings(store, section, open_):
106
167
  v = st.get(k)
107
168
  kind = (knobs.get(k) or {}).get('type')
108
169
  if kind == 'switch': return 'on' if str(v if v is not None else '1').strip() not in ('0', 'false', 'off', '') else 'off'
170
+ if str(v).strip() == '*': return 'every other one set up, in order' # backup_brains' own wildcard, said in words
109
171
  return str(v) if v not in (None, '') else '(not set)'
110
172
  if open_:
111
173
  m = knobs.get(open_) or {'label': open_}
@@ -116,7 +178,8 @@ def _settings(store, section, open_):
116
178
  rows = [(k, m) for k, m in knobs.items() if m.get('group') == section]
117
179
  lines = [f"· {m.get('label') or k}: {value(k)}" for k, m in rows]
118
180
  return (f"SETTINGS · {section.upper()}\n" + ('\n'.join(lines) or 'Its controls are on the desktop.'),
119
- [(m.get('label') or k, {'t': 'browse', 'area': 'settings', 'section': section, 'open': k}) for k, m in rows][:12] + up)
181
+ paged([(m.get('label') or k, {'t': 'browse', 'area': 'settings', 'section': section, 'open': k}) for k, m in rows], up,
182
+ {'t': 'browse', 'area': 'settings', 'section': section}, page))
120
183
  groups = [g for g in schema.get('groups') or [] if any(m.get('group') == g for m in knobs.values())]
121
184
  return ('Settings - pick a section:\n' + '\n'.join(f'· {g}' for g in groups),
122
- [(g, {'t': 'browse', 'area': 'settings', 'section': g}) for g in groups])
185
+ paged([(g, {'t': 'browse', 'area': 'settings', 'section': g}) for g in groups], [], {'t': 'browse', 'area': 'settings'}, page))
@@ -139,12 +139,20 @@ def pipe_list(store, p: dict) -> str:
139
139
  from . import funnel
140
140
  items = [i for i in (funnel.pile(store).get('items') or []) if not i.get('settling')]
141
141
  if not items: return 'The pipe is empty - nothing is waiting on you.'
142
+ # BY THE RAIL'S OWN SECTIONS, the headings the owner sees (funnel.level_of) - each row still says its lane. Grouped by
143
+ # lane, "For later" never appeared: it is a section, not a lane, and "what is waiting in later" was answered "nothing is
144
+ # parked in Later" over four rows sitting under that heading (the owner, 2026-09-30)
145
+ from .remote_assistant import _back_in
142
146
  out = []
143
- for lane in funnel.LANES:
144
- xs = [i for i in items if i['lane'] == lane]
147
+ for sec in ('urgent', 'task', 'agents', 'later', 'reports', 'ideas', 'fyi'):
148
+ xs = [i for i in items if funnel.level_of(i) == sec]
145
149
  if not xs: continue
146
- out.append(f"{funnel.LANE_COUNTED[lane].upper()} ({len(xs)}):")
147
- out += [f" {task_ref(i['tid']) + ' ' if i.get('tid') else ''}{i['who'] + ' - ' if i.get('who') else ''}{_cut(i.get('title'), 100)}" for i in xs[:15]]
150
+ out.append(f"{funnel.SECTION_WORDS[sec].upper()} ({len(xs)}):")
151
+ def row(i):
152
+ back = _back_in(i.get('back_at') or i.get('defer_until')) if sec == 'later' else ''
153
+ return (f" {task_ref(i['tid']) + ' ' if i.get('tid') else ''}{i['who'] + ' - ' if i.get('who') else ''}{_cut(i.get('title'), 100)}"
154
+ f" [{funnel.LANE_WORDS.get(i['lane'], (i['lane'],))[0]}{', back in ' + back if back else ''}]")
155
+ out += [row(i) for i in xs[:15]]
148
156
  if len(xs) > 15: out.append(f' ...and {len(xs) - 15} more')
149
157
  return NL.join(out)
150
158
 
@@ -531,7 +531,8 @@ MORNING_KEY, MORNING_AT = 'phone_morning_line', 'phone_morning_line_at'
531
531
  SCRIPT_LINES = [('Walk me through my tasks', {'t': 'walk'}), ('Set up Taskuary', {'t': 'script', 'script': 'set up Taskuary'}),
532
532
  ('Set up a report', {'t': 'script', 'script': 'set up a report'}),
533
533
  # the sidebar's browse buttons, as picks (doorway_browse): sections, then the list, then one
534
- ('Connections', {'t': 'browse', 'area': 'connections'}), ('Settings', {'t': 'browse', 'area': 'settings'})]
534
+ ('Connections', {'t': 'browse', 'area': 'connections'}), ('Reports', {'t': 'browse', 'area': 'reports'}),
535
+ ('Hub', {'t': 'browse', 'area': 'hub'}), ('Settings', {'t': 'browse', 'area': 'settings'})]
535
536
 
536
537
 
537
538
  def greeting(now=None) -> str:
@@ -771,8 +772,7 @@ def carry_out(store, out: dict, item: dict | None, actor: str = 'owner', lead: s
771
772
  said.append('I could not write that draft here - it is waiting on the task page.')
772
773
  if walk_on:
773
774
  here = (item or {}).get('key') if verb == 'next' else None # Next leaves the table as the desktop's does
774
- nxt = concierge.surface(store, actor=actor, leaving=here, exclude=here)
775
- return '\n\n'.join(said + [turn_text(nxt, store=store)])
775
+ return _on(store, actor, said, leaving=here, exclude=here, done_with=(item or {}).get('key'))
776
776
  return '\n\n'.join(x for x in said if x)
777
777
 
778
778
 
@@ -857,6 +857,29 @@ def receipt_text(store, done: dict, actor: str = 'owner') -> str:
857
857
  return turn_text({'say': turn['say'], 'item': None}, store=store, extra=list(recovery_rows(store, turn['chips'], actor)))
858
858
 
859
859
 
860
+ def _move_on(store, actor: str, leaving: str = None, exclude: str = None, done_with: str = None) -> tuple[dict, str]:
861
+ """What comes after the table - (the next surface, a lead line). WHILE A SECTION IS BEING WALKED the next row of that
862
+ section, whatever put the last one down: Next did, but an act (Make a task, Send to agent, Remind me) fell back to the
863
+ whole walk and put TQ-0001 up in the middle of Walk Reports (2026-09-30 phone test). `done_with` is the key the act settled."""
864
+ from . import concierge, doorway_browse, funnel
865
+ walking = doorway_browse.held(store, asking())
866
+ if walking:
867
+ seen = [*walking.get('seen', []), *[k for k in (leaving, done_with) if k]]
868
+ nxt = doorway_browse.next_in(store, walking['section'], seen)
869
+ if nxt:
870
+ doorway_browse.hold(store, asking(), walking['section'], [*seen, nxt['key']])
871
+ return concierge.surface(store, nxt['key'], actor=actor, leaving=leaving), ''
872
+ doorway_browse.hold(store, asking(), None) # the section ran out: say so, and the walk goes on as normal
873
+ return concierge.surface(store, actor=actor, leaving=leaving, exclude=exclude), funnel.section_done(walking['section'])
874
+ return concierge.surface(store, actor=actor, leaving=leaving, exclude=exclude), ''
875
+
876
+
877
+ def _on(store, actor: str, said: list, extra=None, **kw) -> str:
878
+ """The receipt lines, then what comes next (_move_on) - with the section's own end said when it ran out."""
879
+ nxt, lead = _move_on(store, actor, **kw)
880
+ return '\n\n'.join([x for x in said if x] + [turn_text(nxt, lead=lead, store=store, extra=extra)])
881
+
882
+
860
883
  def _ran(store, prop: dict, done: dict, item: dict | None, actor: str) -> str:
861
884
  """After the run: the receipt, an Undo when it offered one, and the next item when the table was settled."""
862
885
  from . import concierge
@@ -864,7 +887,7 @@ def _ran(store, prop: dict, done: dict, item: dict | None, actor: str) -> str:
864
887
  said = concierge.receipt(store, done, actor)
865
888
  undo = [('Undo', {'t': 'undo'})] if ' Undo: ' in said else []
866
889
  if done.get('status') == 'done' and _settled_the_table(prop, item):
867
- return '\n\n'.join([said, turn_text(concierge.surface(store, actor=actor), store=store, extra=undo)])
890
+ return _on(store, actor, [said], extra=undo, done_with=prop.get('key') or (item or {}).get('key'))
868
891
  if undo: return '\n\n'.join([said, turn_text({}, store=store, extra=undo)])
869
892
  return said
870
893
 
@@ -897,7 +920,7 @@ def run_act(store, act: dict, item: dict | None, actor: str = 'owner') -> str:
897
920
  # a new walk, or one item by name, is not the section being walked
898
921
  if t in ('walk', 'open'): doorway_browse.hold(store, asking(), None)
899
922
  if t == 'browse':
900
- text, rows = doorway_browse.browse(store, act.get('area') or '', act.get('section'), act.get('open'))
923
+ text, rows = doorway_browse.browse(store, act.get('area') or '', act.get('section'), act.get('open'), act.get('page') or 0)
901
924
  return turn_text({'say': text, 'item': None}, store=store, extra=rows)
902
925
  if t == 'next' and doorway_browse.held(store, asking()):
903
926
  here, walking = (item or {}).get('key'), doorway_browse.held(store, asking())
@@ -1008,6 +1031,13 @@ def stuck(store, text: str) -> str:
1008
1031
  return turn_text({'say': text, 'item': None}, store=store, extra=[(concierge.CHIP_WORDS['next'], {'t': 'next'})])
1009
1032
 
1010
1033
 
1034
+ def asking_key(store) -> str:
1035
+ """The key on the table for this chat's walk - what a Remind me just put away."""
1036
+ from . import concierge, general
1037
+ try: return (concierge.restore_current(store, general.dock_task(store, 'owner')[0]['TaskId']) or {}).get('key') or ''
1038
+ except Exception: return ''
1039
+
1040
+
1011
1041
  REMIND_DAYS = (('Tomorrow', 'tomorrow'), ('Next week', '1 week'), ('In 2 weeks', '2 weeks'), ('In a month', '1 month')) # RemindMe.jsx's QUICK
1012
1042
 
1013
1043
 
@@ -1017,13 +1047,13 @@ def _remind(store, act: dict, actor: str) -> str:
1017
1047
  if act.get('idea'):
1018
1048
  from . import assistant
1019
1049
  out = assistant.act(store, int(act['idea']), 'snooze', actor, until=act['until'])
1020
- return '\n\n'.join([f"Put away until {out['when']} - it comes back that morning.", turn_text(concierge.surface(store, actor=actor), store=store)])
1050
+ return _on(store, actor, [f"Put away until {out['when']} - it comes back that morning."], done_with=(asking_key(store) or None))
1021
1051
  out = remind.set_reminder(store, int(act['tid']), act['until'], actor)
1022
1052
  operations.record_direct(store, 'task.defer', int(act['tid']), {'until': act['until']}, actor, out)
1023
1053
  if not out.get('remindAt'): return 'It is back on your rail now.'
1024
1054
  said = f"Away until {out['when']} - it is under Upcoming in Tasks, and back on your rail that morning."
1025
1055
  back = [('Bring it back now', {'t': 'remind', 'tid': act['tid'], 'until': 'none'})]
1026
- return '\n\n'.join([said, turn_text(concierge.surface(store, actor=actor), store=store, extra=back)])
1056
+ return _on(store, actor, [said], extra=back, done_with=(asking_key(store) or None))
1027
1057
 
1028
1058
 
1029
1059
  def _draft(store, item: dict, verb: str, instruction: str):
@@ -1454,6 +1484,19 @@ def summary_rest(store, item: dict | None) -> str:
1454
1484
  return ' '.join(re.split(r'(?<=[.!?])\s+', summary)[1:]).strip()
1455
1485
 
1456
1486
 
1487
+ def _repeats(line: str, shown: list) -> bool:
1488
+ """A line that only says again what is already on the card: its opening is in a shown line, or a shown line's opening is
1489
+ in it. A task written from one pasted paragraph has that paragraph as its title, its message's subject AND its summary,
1490
+ and the card printed it three times (the owner, 2026-09-30, TQ-0887) - the desktop row keeps one (fyiRow.gistFor)."""
1491
+ norm = lambda s: ' '.join(str(s or '').split()).lower().rstrip('…').strip()
1492
+ a = norm(line)
1493
+ if not a: return True
1494
+ for s in shown:
1495
+ b = norm(s)
1496
+ if b and (a[:48] in b or b[:48] in a): return True
1497
+ return False
1498
+
1499
+
1457
1500
  def story_block(store, item: dict | None, draft: str = '', say: str = '', full: bool = False) -> str:
1458
1501
  """The quiet part: a header (state · ref), who asked and what they want, then the agent and its evidence.
1459
1502
  `full`: the owner opened this one to READ it - the whole message, not its opening (full_body)."""
@@ -1483,9 +1526,10 @@ def story_block(store, item: dict | None, draft: str = '', say: str = '', full:
1483
1526
  # what the thing IS, in its own words - a pull request's title and number, an email's subject - and the rest of the
1484
1527
  # summary: the first sentence says who wants what, never what it is (the owner, 2026-09-28: "at least the title")
1485
1528
  subj = subject_of(store, it)
1486
- if subj and re.sub(r'^(PR |Issue )?#\d+( ·)?\s*', '', subj).lower() not in (said or '').lower(): lines.append(subj)
1529
+ if subj and re.sub(r'^(PR |Issue )?#\d+( ·)?\s*', '', subj).lower() not in (said or '').lower() and not _repeats(subj, [said]):
1530
+ lines.append(_cut(subj, 280))
1487
1531
  rest = summary_rest(store, it)
1488
- if rest: lines.append(_cut(rest, 280))
1532
+ if rest and not _repeats(rest, [said, subj]): lines.append(_cut(rest, 280))
1489
1533
  if not it.get('tid') and say and kind != 'agentdone' and (not said or said.lower() not in say.lower()): lines.append(say)
1490
1534
  # their own words, when nothing of yours answers them yet (a draft puts them behind More)
1491
1535
  whole = full_body(store, it) if full else ''
@@ -280,6 +280,7 @@ class DecideBody(BaseModel):
280
280
  class CodeBody(BaseModel):
281
281
  repo: str | None = None; agent: str | None = None
282
282
  model: str | None = None; instruction: str | None = None
283
+ brain: str | None = None # WHICH CLI - continue_task read it, but nothing could ever send it
283
284
  class DocBody(BaseModel): content: str
284
285
  class SettingBody(BaseModel): name: str; value: str
285
286
  class SourceBody(BaseModel):
@@ -1490,7 +1491,10 @@ def continue_session(task_id: int, body: CodeBody = None):
1490
1491
  try:
1491
1492
  session = hub_term.start_on_task(store, task_id, row['Agent'], (body.model if body else None),
1492
1493
  (body.instruction if body else None), ACTOR,
1493
- cwd=row['Cwd'], resume=row['ExtId'])
1494
+ cwd=row['Cwd'], resume=row['ExtId'],
1495
+ # the id belongs to the CLI that made it: resuming a codex conversation on the default
1496
+ # brain ran `claude --resume <codex id>` - "No conversation found with session ID"
1497
+ brain=row.get('Brain') or None)
1494
1498
  except (ValueError, RuntimeError, FileNotFoundError) as e:
1495
1499
  raise HTTPException(422, str(e))
1496
1500
  store.audit('task', task_id, 'continue-session', ACTOR, detail={'agent': row['Agent'], 'fromSid': row['Sid']})
@@ -1525,8 +1529,22 @@ def continue_work(task_id: int, body: ContinueBody = None):
1525
1529
  return {'continued': True, 'taskId': task_id, 'kind': 'general'}
1526
1530
  note = with_images(note, imgs).strip()
1527
1531
  row, _why = _resumable(task_id)
1528
- if row: out = continue_session(task_id, CodeBody(instruction=note or None))
1529
- else: out = continue_task(task_id, CodeBody(instruction=(f'FROM THE OWNER: {note}\n\n' if note else '') + continuity.RESUME_PROMPT)) # their words lead
1532
+ # CONTINUE IS THE SAME CLI (the owner, 2026-09-30: "it should start as codex if i hit continue of course"): the one that made
1533
+ # the conversation, else the one that last worked the task - never whatever the default happens to be today
1534
+ last = row or store.last_transcript(task_id) or {}
1535
+ brain = (last.get('Brain') or None) if isinstance(last, dict) else None
1536
+ fresh = lambda: continue_task(task_id, CodeBody(brain=brain, instruction=(f'FROM THE OWNER: {note}\n\n' if note else '') + continuity.RESUME_PROMPT)) # their words lead
1537
+ if row:
1538
+ # the conversation belongs to the CLI that made it; when THAT CLI cannot open now (out of sessions, signed out), a fresh
1539
+ # session seeded with the handover is the way on - not an error (the owner, 2026-09-30, TQ-0887: codex made it, codex was
1540
+ # unavailable, and every Continue failed)
1541
+ try: out = continue_session(task_id, CodeBody(instruction=note or None))
1542
+ except HTTPException as e:
1543
+ if e.status_code != 422: raise
1544
+ store.add_comment(task_id, 'router', 'agent', f"{brain or row['Agent']} could not reopen its conversation ({e.detail}); "
1545
+ f"starting a fresh {brain or 'agent'} session with the handover instead.")
1546
+ row, out = None, fresh()
1547
+ else: out = fresh()
1530
1548
  store.audit('task', task_id, 'continue-work', ACTOR, detail={'kind': 'coding', 'resumed': bool(row), 'note': bool(note)})
1531
1549
  return {'continued': True, 'taskId': task_id, 'kind': 'coding', 'resumed': bool(row), **(out if isinstance(out, dict) else {})}
1532
1550