threadkeeper 0.19.0__tar.gz → 0.19.1__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 (290) hide show
  1. {threadkeeper-0.19.0/threadkeeper.egg-info → threadkeeper-0.19.1}/PKG-INFO +173 -51
  2. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/README.md +172 -50
  3. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/pyproject.toml +1 -1
  4. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_agent_status.py +36 -17
  5. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_config_settings.py +3 -0
  6. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_curator.py +187 -5
  7. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_applier.py +388 -8
  8. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_daemon.py +163 -0
  9. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_identity.py +2 -0
  10. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_denylist.py +1 -1
  11. threadkeeper-0.19.1/tests/test_mcp_protocol_conformance.py +235 -0
  12. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_mcp_resources_prompts.py +160 -0
  13. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_eval.py +84 -4
  14. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_nudges.py +4 -7
  15. threadkeeper-0.19.1/tests/test_project_scope.py +113 -0
  16. threadkeeper-0.19.1/tests/test_session_read_purity.py +104 -0
  17. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_shadow_review.py +6 -1
  18. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_hint.py +4 -5
  19. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_hint.py +9 -16
  20. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_tool_annotations.py +53 -1
  21. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_tools_smoke.py +1 -0
  22. threadkeeper-0.19.1/tests/test_tracing.py +237 -0
  23. threadkeeper-0.19.1/tests/test_workflow_retention.py +255 -0
  24. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/_mcp.py +84 -3
  25. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/_spawn_wrap.py +9 -3
  26. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/base.py +1 -0
  27. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/agent_status.py +37 -20
  28. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/brief.py +50 -41
  29. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/candidate_reviewer.py +9 -6
  30. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/config.py +29 -6
  31. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/curator.py +214 -76
  32. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/curator_snapshots.py +44 -3
  33. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/db.py +246 -16
  34. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/dialectic_miner.py +10 -5
  35. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/dialectic_validator.py +4 -2
  36. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/elicitation.py +3 -0
  37. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/embeddings.py +12 -4
  38. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/evolve_applier.py +426 -53
  39. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/evolve_daemon.py +60 -27
  40. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/forget.py +13 -0
  41. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/identity.py +13 -3
  42. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/ingest.py +20 -4
  43. threadkeeper-0.19.1/threadkeeper/project_scope.py +204 -0
  44. threadkeeper-0.19.1/threadkeeper/protocol.py +186 -0
  45. threadkeeper-0.19.1/threadkeeper/read_context.py +24 -0
  46. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/retention.py +5 -1
  47. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/retrieval.py +34 -8
  48. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/server.py +1 -0
  49. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/shadow_review.py +4 -1
  50. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/spawn_budget.py +1 -0
  51. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/identity.py +6 -0
  52. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tool_schemas.py +1 -0
  53. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/agent_status.py +15 -2
  54. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/concepts.py +25 -10
  55. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/core_memory.py +43 -16
  56. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/curator.py +7 -4
  57. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dashboard.py +6 -0
  58. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/db_maintenance.py +19 -1
  59. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dialectic.py +39 -13
  60. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dialog.py +24 -7
  61. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/distill.py +26 -10
  62. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/evolve_applier.py +33 -20
  63. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/extract.py +44 -25
  64. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/pickup.py +4 -3
  65. threadkeeper-0.19.1/threadkeeper/tools/project_scope.py +33 -0
  66. threadkeeper-0.19.1/threadkeeper/tools/resources.py +460 -0
  67. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/session.py +8 -3
  68. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/shadow_review.py +28 -11
  69. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/spawn.py +64 -9
  70. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/style.py +14 -2
  71. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/sync.py +2 -2
  72. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/threads.py +60 -22
  73. threadkeeper-0.19.1/threadkeeper/tracing.py +572 -0
  74. threadkeeper-0.19.1/threadkeeper/workflow_artifacts.py +568 -0
  75. {threadkeeper-0.19.0 → threadkeeper-0.19.1/threadkeeper.egg-info}/PKG-INFO +173 -51
  76. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/SOURCES.txt +10 -0
  77. threadkeeper-0.19.0/tests/test_session_read_purity.py +0 -51
  78. threadkeeper-0.19.0/threadkeeper/tools/resources.py +0 -100
  79. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/LICENSE +0 -0
  80. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/setup.cfg +0 -0
  81. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_adapters.py +0 -0
  82. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_antigravity_ingest.py +0 -0
  83. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_auto_update.py +0 -0
  84. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_backup.py +0 -0
  85. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_brief_footprint.py +0 -0
  86. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_brief_sections.py +0 -0
  87. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_candidate_reviewer.py +0 -0
  88. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ci_parallel.py +0 -0
  89. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_concepts.py +0 -0
  90. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_config_watcher.py +0 -0
  91. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_core_memory.py +0 -0
  92. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_host_config.py +0 -0
  93. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_host_integration.py +0 -0
  94. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_liveness.py +0 -0
  95. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_daemon_state.py +0 -0
  96. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dashboard.py +0 -0
  97. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_compact.py +0 -0
  98. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_contention.py +0 -0
  99. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_leak_guard.py +0 -0
  100. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_migration_fts.py +0 -0
  101. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_runtime.py +0 -0
  102. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_db_schema.py +0 -0
  103. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_delegated_search.py +0 -0
  104. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic.py +0 -0
  105. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_feed_tools.py +0 -0
  106. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_miner.py +0 -0
  107. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_observation_resolve.py +0 -0
  108. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_recompute.py +0 -0
  109. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_tier.py +0 -0
  110. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialectic_validator.py +0 -0
  111. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_dialog_fts_external.py +0 -0
  112. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_documentation_inventory.py +0 -0
  113. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_egress_policy.py +0 -0
  114. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embed_routing.py +0 -0
  115. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embedding_generation.py +0 -0
  116. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embedding_model_revision.py +0 -0
  117. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_embedding_storage_dedup.py +0 -0
  118. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_error_paths.py +0 -0
  119. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_eval_harness.py +0 -0
  120. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_2.py +0 -0
  121. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_3.py +0 -0
  122. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_43.py +0 -0
  123. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_evolve_apply_45.py +0 -0
  124. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_extract_daemon.py +0 -0
  125. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_extract_dedup.py +0 -0
  126. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_forget.py +0 -0
  127. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_github_budget.py +0 -0
  128. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_github_safety.py +0 -0
  129. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_helpers.py +0 -0
  130. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_hook_child_guard.py +0 -0
  131. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_embed.py +0 -0
  132. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_env.py +0 -0
  133. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_main.py +0 -0
  134. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_host_wedged.py +0 -0
  135. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_hybrid_retrieval.py +0 -0
  136. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_i18n_multilang.py +0 -0
  137. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_cursor.py +0 -0
  138. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_secret_redaction.py +0 -0
  139. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_status.py +0 -0
  140. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_ingest_transactions.py +0 -0
  141. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_lesson_violations.py +0 -0
  142. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_lessons.py +0 -0
  143. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_mcp_sdk_compat.py +0 -0
  144. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_mcp_skills_extension.py +0 -0
  145. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_authority_lifecycle.py +0 -0
  146. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_compatibility.py +0 -0
  147. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_guard.py +0 -0
  148. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_memory_guard_host.py +0 -0
  149. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_menubar_app.py +0 -0
  150. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_missed_spawns.py +0 -0
  151. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_model_catalog.py +0 -0
  152. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_notify_daemon.py +0 -0
  153. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_onnx_embeddings.py +0 -0
  154. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_panel.py +0 -0
  155. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_permissions.py +0 -0
  156. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_pickup.py +0 -0
  157. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_probe_daemon.py +0 -0
  158. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_process_health.py +0 -0
  159. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_release_workflows.py +0 -0
  160. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_retention.py +0 -0
  161. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_review_prompts.py +0 -0
  162. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_search_fts_punctuation.py +0 -0
  163. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_setup.py +0 -0
  164. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_single_flight_prompt_prefixes.py +0 -0
  165. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_passive_tier.py +0 -0
  166. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_tier.py +0 -0
  167. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_updater.py +0 -0
  168. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_use_parser.py +0 -0
  169. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skill_watcher.py +0 -0
  170. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_skills.py +0 -0
  171. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_background_cwd.py +0 -0
  172. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_budget.py +0 -0
  173. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_child_env.py +0 -0
  174. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_codex_stdin.py +0 -0
  175. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_config.py +0 -0
  176. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_permission_gate.py +0 -0
  177. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_reap.py +0 -0
  178. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_result.py +0 -0
  179. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_slim.py +0 -0
  180. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_watchdog.py +0 -0
  181. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_worktree_isolation.py +0 -0
  182. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_spawn_wrap.py +0 -0
  183. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_capture.py +0 -0
  184. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_identity.py +0 -0
  185. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_migrate.py +0 -0
  186. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_protocol.py +0 -0
  187. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_reset_node.py +0 -0
  188. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_sync_transport.py +0 -0
  189. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_task_retention.py +0 -0
  190. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_task_spool.py +0 -0
  191. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_thin_session.py +0 -0
  192. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_thread_janitor.py +0 -0
  193. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_threads.py +0 -0
  194. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_validate_threads.py +0 -0
  195. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_vec_search.py +0 -0
  196. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/tests/test_verify_ingest.py +0 -0
  197. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/__init__.py +0 -0
  198. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/_setup.py +0 -0
  199. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/__init__.py +0 -0
  200. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/_hook_helpers.py +0 -0
  201. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/antigravity.py +0 -0
  202. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/claude_code.py +0 -0
  203. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/claude_desktop.py +0 -0
  204. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/codex.py +0 -0
  205. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/copilot.py +0 -0
  206. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/adapters/vscode.py +0 -0
  207. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/agent_metadata.py +0 -0
  208. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/Info.plist +0 -0
  209. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/README.md +0 -0
  210. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/ThreadKeeperAgentStatus.swift +0 -0
  211. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/build.sh +0 -0
  212. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/assets/macos-agent-status/install.sh +0 -0
  213. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/authority.py +0 -0
  214. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/auto_update.py +0 -0
  215. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/backup.py +0 -0
  216. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/config_io.py +0 -0
  217. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/config_watcher.py +0 -0
  218. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/daemon_liveness.py +0 -0
  219. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/daemon_state.py +0 -0
  220. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/daemon_supervisor.py +0 -0
  221. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/egress.py +0 -0
  222. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/eval/__init__.py +0 -0
  223. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/eval/__main__.py +0 -0
  224. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/eval/harness.py +0 -0
  225. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/extract_daemon.py +0 -0
  226. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/github_budget.py +0 -0
  227. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/github_safety.py +0 -0
  228. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/harvest.py +0 -0
  229. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/helpers.py +0 -0
  230. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/host.py +0 -0
  231. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/host_embed.py +0 -0
  232. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/i18n.py +0 -0
  233. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/lesson_violations.py +0 -0
  234. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/lessons.py +0 -0
  235. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/link_health.py +0 -0
  236. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/mcp_skills.py +0 -0
  237. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/memory_compat.py +0 -0
  238. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/memory_guard.py +0 -0
  239. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/menubar_app.py +0 -0
  240. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/migrate_embeddings.py +0 -0
  241. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/model_catalog.py +0 -0
  242. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/notify.py +0 -0
  243. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/nudges.py +0 -0
  244. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/permissions.py +0 -0
  245. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/probe_daemon.py +0 -0
  246. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/process_health.py +0 -0
  247. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/review_prompts.py +0 -0
  248. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/search_proxy.py +0 -0
  249. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/skill_audit.py +0 -0
  250. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/skill_updater.py +0 -0
  251. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/skill_watcher.py +0 -0
  252. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/spawn_config.py +0 -0
  253. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/spawn_result.py +0 -0
  254. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/__init__.py +0 -0
  255. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/capture.py +0 -0
  256. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/daemon.py +0 -0
  257. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/migrate.py +0 -0
  258. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/protocol.py +0 -0
  259. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/reset_node.py +0 -0
  260. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/sync/server.py +0 -0
  261. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/task_spool.py +0 -0
  262. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/thread_janitor.py +0 -0
  263. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/__init__.py +0 -0
  264. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/authority.py +0 -0
  265. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/candidate_reviewer.py +0 -0
  266. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/config_watch.py +0 -0
  267. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/consolidate.py +0 -0
  268. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/correlation.py +0 -0
  269. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/dialectic_feed.py +0 -0
  270. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/evolve_research.py +0 -0
  271. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/forget.py +0 -0
  272. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/graph.py +0 -0
  273. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/invariants.py +0 -0
  274. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/lessons.py +0 -0
  275. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/memory_guard.py +0 -0
  276. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/missed_spawns.py +0 -0
  277. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/panel.py +0 -0
  278. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/peers.py +0 -0
  279. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/probes.py +0 -0
  280. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/process_health.py +0 -0
  281. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/prompts.py +0 -0
  282. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/skills.py +0 -0
  283. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/tools/validate.py +0 -0
  284. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/trash.py +0 -0
  285. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/verify_ingest.py +0 -0
  286. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper/wikilinks.py +0 -0
  287. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/dependency_links.txt +0 -0
  288. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/entry_points.txt +0 -0
  289. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/requires.txt +0 -0
  290. {threadkeeper-0.19.0 → threadkeeper-0.19.1}/threadkeeper.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: threadkeeper
3
- Version: 0.19.0
3
+ Version: 0.19.1
4
4
  Summary: Multi-agent shared brain across Claude Code/Desktop, Codex, Antigravity CLI, Copilot, and VS Code. Cross-session memory, self-improving skill loops, inter-agent signaling — one local MCP server.
5
5
  Author: thread-keeper contributors
6
6
  License: MIT
@@ -232,7 +232,7 @@ read/act split, plus MCP elicitation for host-native confirmations:
232
232
  | Primitive | Control | What thread-keeper exposes | When to use |
233
233
  |---|---|---|---|
234
234
  | **Tools** | model-controlled (may act) | the full surface — `brief`, `note`, `spawn`, `search`, `curator_review`, `wikilink_health`, … | the agent decides to call them |
235
- | **Resources** | application-controlled, read-only | `memory://brief`, `memory://context`, `memory://dashboard`, `memory://agent-status` | the **host** attaches/pulls them automatically |
235
+ | **Resources** | application-controlled, read-only | `memory://brief`, `memory://context`, `memory://dashboard`, `memory://agent-status` | the **host** attaches/pulls them automatically; capable hosts may subscribe |
236
236
  | **Prompts** | user-controlled templates | `review_recent_threads`, `run_library_curation`, `audit_threadkeeper` | the user runs them (Claude Code: `/mcp__thread-keeper__<name>`) |
237
237
 
238
238
  **Resources** back the genuinely read-only memory views with the same render
@@ -322,6 +322,28 @@ override wins over `.env`):
322
322
  THREADKEEPER_MEMORY_EGRESS=same-vendor
323
323
  ```
324
324
 
325
+ ### Project memory boundaries
326
+
327
+ Memory is also isolated by repository. thread-keeper derives a path-free
328
+ `prj_…` namespace from the repository remote (or, when no remote exists, its
329
+ Git history), so ordinary moves and Git worktrees retain one identity without
330
+ storing a local path. New project memory is scoped to that namespace; portable
331
+ memory must be explicitly written as `global` or `shared`.
332
+
333
+ `brief()`, `search()`, `dialog_search()`, resources, and learning-loop inputs
334
+ read the current project plus explicit global/shared rows. Set
335
+ `cross_project=True` on `search` or `dialog_search` only for deliberate
336
+ cross-project recall. Those results show `scope=`/`project=` provenance and
337
+ write a `cross_project_recall` audit event. The `memory_scope_status()` tool
338
+ shows the current namespace and the migration accounting.
339
+
340
+ Existing databases are migrated conservatively: rows without reliable
341
+ repository provenance are marked `unresolved`, excluded from automatic recall,
342
+ and listed in the migration report until an operator classifies them. This
343
+ boundary controls *which local memory is recalled*; it is separate from
344
+ `THREADKEEPER_MEMORY_EGRESS`, which controls whether personal memory may be
345
+ sent to another model provider.
346
+
325
347
  ---
326
348
 
327
349
  ## Core systems
@@ -764,15 +786,20 @@ for semantic review. System and installed-plugin sources are resolved from
764
786
  their read-only caches rather than misreported as missing mirrors; telemetry
765
787
  rows with no real `SKILL.md` remain explicit orphans. The same inventory also
766
788
  flags a dense lesson subtopic when at least
767
- `THREADKEEPER_CURATOR_PROMOTION_MIN_LESSONS` lessons (default 3) share a pair
768
- of meaningful title terms. A non-protected candidate must become one validated,
769
- checklist-style canonical skill before its source lessons are retired; protected
770
- clusters are left for human review. A read-only research child reads every
771
- complete skill and relevant support file, performs current web research against
772
- official docs and comparable public skills, then writes a bounded
773
- `RESEARCH-<pass>-batch-NNN-of-MMM.json` handoff through a destination-scoped
774
- tool. A separate web-free evaluator receives that handoff as fenced, untrusted
775
- data and writes numbered per-skill verdicts to
789
+ `THREADKEEPER_CURATOR_PROMOTION_MIN_LESSONS` lessons (default 3) share two
790
+ concrete title terms and a non-generic body mechanism. Generic joins and
791
+ domain-wide/high-document-frequency title words cannot form a candidate. The
792
+ inventory and `curator_review_status()` report emitted/rejected counts and
793
+ rejection reasons, so the rule can be tuned from production data. A
794
+ non-protected candidate must become one validated, checklist-style canonical
795
+ skill before its source lessons are retired; protected clusters are left for
796
+ human review. The evaluator reads every complete skill and relevant support
797
+ file, but has no web tools. External research is off by default. With explicit
798
+ `THREADKEEPER_CURATOR_WEB_RESEARCH=1`, a separate Claude-only researcher gets
799
+ only fixed public compatibility queries, `WebSearch`, `WebFetch`, and one
800
+ parent-authorized handoff writer; it cannot read local memory or the
801
+ repository. The evaluator receives that handoff as fenced, untrusted data and
802
+ writes numbered per-skill verdicts to
776
803
  `~/.threadkeeper/curator/REPORT-<isodate>.md` for a one-batch pass or
777
804
  `REPORT-<isodate>-batch-NNN-of-MMM.md` for a multi-batch pass: KEEP / REPAIR /
778
805
  UPDATE / MERGE / SPLIT / DEPRECATE / DELETE / CROSS_LINK / HUMAN_REVIEW.
@@ -874,7 +901,11 @@ a recoverable snapshot under
874
901
  `~/.threadkeeper/curator/snapshots/<pass-id>/`). The snapshot contains
875
902
  `lessons.md`, copied in-scope skill dirs, a `manifest.json`, and per-action
876
903
  tombstones for curator prunes/deletes. Retention is bounded by
877
- `THREADKEEPER_CURATOR_SNAPSHOT_RETENTION` (default 10, current pass always kept).
904
+ `THREADKEEPER_CURATOR_SNAPSHOT_RETENTION` (default 10) for legacy/direct
905
+ snapshots. Daemon-owned snapshots instead follow the coordinated workflow
906
+ retention policy, so their pass, report, manifest, and recovery archive cannot
907
+ age out on different schedules; active work and an endorsed report that has not
908
+ been applied always keep recovery material.
878
909
  Use `curator_restore(pass_id, lesson_slug="...")` or
879
910
  `curator_restore(pass_id, skill_name="...")` to restore an item from a snapshot.
880
911
  As a prevention layer before recovery is needed, a destructive Curator pass
@@ -1011,15 +1042,27 @@ with that name instead of minting overlapping roadmap PRs.
1011
1042
 
1012
1043
  The Evolve applier is the downstream implementer. `evolve_apply_roadmap_issue()`
1013
1044
  picks one open GitHub issue at a time (`roadmap` label first, then FIFO), but
1014
- the automatic pass first scans already-open same-repo applier PRs for GitHub
1015
- merge conflicts. A conflicted `roadmap/…` or `evolve/…` PR is repaired before
1016
- any new issue/report/evolve work is started; if the PR sweep itself cannot read
1017
- GitHub state, the pass fails closed instead of taking fresh work blind. The
1018
- conflict-repair child checks out the existing PR branch, merges the current
1019
- base branch, resolves conflicts, runs the full suite, and pushes back to the
1020
- same branch. It then waits for GitHub checks on the pushed PR head and runs
1021
- `gh pr merge --squash --delete-branch`, so GitHub lands the repaired PR into
1022
- `main` through branch protection rather than a raw local `git push origin main`.
1045
+ the automatic pass first sweeps the open PRs authored by the account
1046
+ thread-keeper's `gh` acts as — yours: applier, reviewer, and hand-made PRs
1047
+ alike. A PR from any other account (a collaborator, a bot, a fork) is never
1048
+ updated, repaired, or merged. If the PR sweep itself cannot read GitHub state
1049
+ or the `gh` account, the pass fails closed instead of taking fresh work blind.
1050
+ The sweep squash-merges the oldest non-draft PR GitHub reports `CLEAN` (up to
1051
+ date, required checks green) through the protected merge API, pinned to the
1052
+ head SHA it saw green, and then asks GitHub to update the oldest `BEHIND` one —
1053
+ the "Update branch" button — so CI reruns against the new base. Open
1054
+ work in progress as a draft: drafts are never merged. Strict branch
1055
+ protection lets only one PR merge per base commit, so PRs land one at a time,
1056
+ oldest first. Between full passes the daemon repeats only this cheap landing
1057
+ sweep every 15 minutes, so a green PR lands minutes after its checks finish;
1058
+ it skips while any reviewer/applier git writer runs. A conflicted applier PR
1059
+ (`roadmap/…` or `evolve/…` head branch in this repository) is repaired before
1060
+ any new issue/report/evolve work is started: the conflict-repair child checks
1061
+ out the existing PR branch, merges the current base branch, resolves
1062
+ conflicts, runs the full suite, and pushes back to the same branch, then
1063
+ stops; the landing sweep merges it once it is green. A hand-made PR with
1064
+ conflicts, and red or otherwise blocked PRs, wait for a human. Set
1065
+ `THREADKEEPER_EVOLVE_AUTOLAND=0` to leave every merge to a human.
1023
1066
  The roadmap issue child skips issues carrying denylisted human-gate labels,
1024
1067
  skips issues with an active Evolve claim comment, posts its own claim comment
1025
1068
  before spawning, and advances to the next issue when an issue-local dispatch
@@ -1054,9 +1097,13 @@ task’s tree. This prevents unrelated unfinished tests from blocking every PR
1054
1097
  repair. Ignored files (including `.venv`) and explicit operator checkouts stay
1055
1098
  in place; live writers prevent recovery, and backup failures block dispatch.
1056
1099
  Each managed-checkout child fetches the
1057
- configured branch only to retrieve the configured immutable commit, then
1058
- prepares or resumes its deterministic local/remote feature branch from
1059
- `THREADKEEPER_EVOLVE_REPO_COMMIT`, never from the branch's moving tip. Retries
1100
+ configured branch, prepares or resumes its deterministic local/remote feature
1101
+ branch from the freshly fetched `origin/<THREADKEEPER_EVOLVE_REPO_BRANCH>` tip,
1102
+ rebases onto it, and re-syncs the managed venv to that branch's declared
1103
+ dependencies. `THREADKEEPER_EVOLVE_REPO_COMMIT` bounds only what the parent
1104
+ provisions and parks the checkout at; it is never a branch base, because a base
1105
+ that never moves cut every applier PR from one stale commit and each PR was
1106
+ born conflicted with `main`. Retries
1060
1107
  therefore validate prior branch work instead of discovering a branch-name
1061
1108
  collision after changing the base checkout. A shared git-writer running-task
1062
1109
  check prevents the privileged reviewer audit and code/PR applier from
@@ -1349,7 +1396,13 @@ The most-used env knobs (full list in `threadkeeper/config.py`):
1349
1396
  | `THREADKEEPER_PROBE_RESULT_RETENTION_DAYS` | 0 | prune old `probe_results` and refresh reliability aggregates; 0 keeps forever |
1350
1397
  | `THREADKEEPER_RETENTION_WAL_CHECKPOINT` | false | run `PRAGMA wal_checkpoint(TRUNCATE)` during retention passes |
1351
1398
  | `THREADKEEPER_RETENTION_VACUUM_AFTER_ROWS` | 0 | run `VACUUM` after a pass deletes at least this many rows; 0 disables VACUUM |
1399
+ | `THREADKEEPER_WORKFLOW_RETENTION_DAYS` | 30 | age protection for terminal Curator passes and consumed Evolve research handoffs; `0` disables the age bound |
1400
+ | `THREADKEEPER_WORKFLOW_RETENTION_COUNT` | 100 | newest terminal Curator passes and research handoffs protected by count; `0` disables the count bound |
1352
1401
  | `THREADKEEPER_MEMORY_EGRESS` | `all` | cross-provider scope for personal-class memory (verbatim quotes + dialectic user-model) in `brief()`. `all` = current behavior, egress to whichever vendor backs the consuming CLI. `same-vendor` = personal renders only for Claude/Anthropic, omitted for OpenAI/Google/Microsoft CLIs. `work-only` = personal never rendered, any vendor. See [Memory egress](#memory-egress-cross-provider-privacy) |
1402
+ | `THREADKEEPER_OTEL_ENABLED` | false | enable privacy-safe OTLP tracing only when an endpoint is also configured |
1403
+ | `THREADKEEPER_OTEL_ENDPOINT` | "" | OTLP/HTTP collector trace endpoint, normally `https://collector.example/v1/traces` |
1404
+ | `THREADKEEPER_OTEL_EXPORT_TIMEOUT_S` | 2 | collector request timeout; export happens outside the local workflow |
1405
+ | `THREADKEEPER_OTEL_EXPORT_QUEUE_SIZE` | 256 | bounded per-process span queue (1–2048); oldest queued spans are dropped under pressure |
1353
1406
  | `THREADKEEPER_AUTO_REVIEW` | "" (off) | auto-review on `close_thread` |
1354
1407
  | `THREADKEEPER_AUTO_UPDATE_INTERVAL_S` | 86400 | MCP self-update check interval; 0 disables |
1355
1408
  | `THREADKEEPER_AUTO_UPDATE_RESTART` | "1" | exit MCP process after an update passes setup/import smoke checks so the host restarts on new code |
@@ -1383,7 +1436,7 @@ The most-used env knobs (full list in `threadkeeper/config.py`):
1383
1436
  | `THREADKEEPER_CURATOR_INTERVAL_S` | 259200 | deep curator audit every three days; set `0` to disable |
1384
1437
  | `THREADKEEPER_CURATOR_MANAGE_FOREGROUND_SKILLS` | 0 | allow snapshot-scoped Curator repair/merge/delete of foreground skills; pinned/untracked skills remain protected |
1385
1438
  | `THREADKEEPER_CURATOR_MIN_LESSONS` | 3 | min lessons before curator engages |
1386
- | `THREADKEEPER_CURATOR_WEB_RESEARCH` | `1` (on) | run a read-only web research child per batch before the web-free evaluator; `0` skips research (the evaluator uses local evidence only) |
1439
+ | `THREADKEEPER_CURATOR_WEB_RESEARCH` | `0` (off) | explicit consent for the isolated Curator web researcher; it receives only fixed public compatibility queries, while foreground/private/unclassified entries use `HUMAN_REVIEW` |
1387
1440
  | `THREADKEEPER_CURATOR_DESTRUCTIVE` | `1` (on) | curator child writes its REPORT then applies its own PATCH/PRUNE/CONSOLIDATE directly (incl. `lesson_remove` for prune/consolidate); set `0` for advisory REPORT-only. `[PROTECTED]` entries are refused server-side |
1388
1441
  | `THREADKEEPER_CURATOR_MAX_DESTRUCTIVE_PER_PASS` | 10 | shared server-side ceiling for one destructive Curator pass across `lesson_remove` and `skill_manage(action='delete')`; `0` disables autonomous deletes and foreground deletes bypass it |
1389
1442
  | `THREADKEEPER_CURATOR_SNAPSHOT_RETENTION` | 10 | number of destructive curator pre-mutation snapshots to retain under `<reports_dir>/snapshots`; current pass is always retained |
@@ -1433,6 +1486,7 @@ The most-used env knobs (full list in `threadkeeper/config.py`):
1433
1486
  | `THREADKEEPER_EVOLVE_REVIEW_INTERVAL_S` | 0 (off) | evolve-reviewer daemon tick (s); audits thread-keeper for safety/leaks/optimization/new ideas, updates roadmap/issues, and includes legacy evolve suggestions as input. Runs as two alternating phases — read-only web research, then a privileged web-free audit that consumes the fenced research digest (#79) — so a full cycle spans two ticks |
1434
1487
  | `THREADKEEPER_EVOLVE_REVIEW_BACKLOG_MAX` | 25 | max open, not-yet-applied `roadmap`-label issues before the issue-creating audit is skipped and records `backlog_saturated`; skip-labelled and untrusted-author roadmap issues still count; `0` disables the cap |
1435
1488
  | `THREADKEEPER_EVOLVE_APPLY_INTERVAL_S` | 0 (off) | evolve-applier daemon tick (s); implements one open GitHub issue at a time, then falls back to Curator reports and promoted legacy evolve suggestions. Empty checks are throttled between intervals; actionable work and manual apply tools still dispatch |
1489
+ | `THREADKEEPER_EVOLVE_AUTOLAND` | true | land open non-draft PRs authored by the account `gh` acts as: squash-merge one once GitHub reports it up to date with required checks green, and update one that fell behind the base. Other accounts' PRs are never touched. `0`/`false` leaves every merge to a human |
1436
1490
  | `THREADKEEPER_EVOLVE_REPO_ROOT` | (auto) | absolute path to the thread-keeper git checkout the evolve reviewer/applier branch, test, and open PRs against. When empty, the repo is resolved automatically: the package's parent dir for an editable `install.sh`, else a managed checkout under the DB dir that is auto-cloned on first use. Set this to pin an explicit checkout |
1437
1491
  | `THREADKEEPER_EVOLVE_AUTO_CLONE` | true | auto-provision a managed checkout that runs remote `pip install -e` and tests; set `0`/`false` on shared or multi-user hosts unless that remote-code-execution boundary is explicitly accepted |
1438
1492
  | `THREADKEEPER_EVOLVE_REPO_URL` | upstream repo | HTTPS `github.com` source for the managed clone; restart-only, and other hosts/schemes are refused |
@@ -1562,6 +1616,38 @@ Three tools keep the memory tidy. `consolidate()` and `forget()` default to
1562
1616
 
1563
1617
  ## Telemetry
1564
1618
 
1619
+ ### Privacy-safe OTLP traces
1620
+
1621
+ OTLP export is **off by default**. To opt in, set both
1622
+ `THREADKEEPER_OTEL_ENABLED=1` and `THREADKEEPER_OTEL_ENDPOINT` to an
1623
+ OTLP/HTTP `/v1/traces` endpoint. ThreadKeeper sends OTLP JSON asynchronously;
1624
+ collector failure, timeout, or a full queue never delays a local MCP call,
1625
+ spawn, watchdog action, or SQLite write.
1626
+
1627
+ One spawned workflow is linked as `MCP spawn → workflow → agent → child MCP
1628
+ operation`. The W3C trace context is saved with the task and passed only in the
1629
+ private child environment (and its slim MCP config), never in a prompt or CLI
1630
+ argument. A watchdog continuation uses the prior agent span as its parent, so
1631
+ retries remain in the same trace.
1632
+
1633
+ The exporter has a fixed allowlist: operation/tool identifier, latency and
1634
+ queue wait, provider/model identifiers, input/output/total tokens, USD cost,
1635
+ retry count, and terminal outcome. Operation names are fixed; tool/provider
1636
+ identifiers are limited to 64 safe characters, model identifiers to 96, and a
1637
+ process exports at most 64 distinct model values (later values become
1638
+ `unknown`).
1639
+ Everything else is excluded by construction: prompts, MCP arguments/results,
1640
+ memory bodies, user quotes, credentials, paths, task logs, and SQLite event
1641
+ summaries are never span attributes.
1642
+
1643
+ The local SQLite event ledger remains the source of truth. It retains only the
1644
+ opaque trace linkage beside a task row, so its existing task-retention policy
1645
+ also removes that linkage. Configure collector retention at the collector; no
1646
+ trace payload is persisted locally. If traces do not arrive, first verify the
1647
+ endpoint includes `/v1/traces`; then inspect collector connectivity. A full
1648
+ queue intentionally drops its oldest pending spans rather than growing memory
1649
+ or blocking the workflow.
1650
+
1565
1651
  - **`mp_dashboard(window_days=7)`** — one-call rollup of the whole
1566
1652
  system, read-only. Three sections: **stores** (threads by state,
1567
1653
  notes/dialog/distill/concepts counts, skills + claims by tier,
@@ -1702,6 +1788,19 @@ the high-volume tables (`dialog_messages`, `dialog_fts`, `dialog_vec`,
1702
1788
  `signals`, `events`, `tasks`, `probe_results`) so growth is visible before it
1703
1789
  becomes a problem.
1704
1790
 
1791
+ Terminal Curator passes own their frozen batch text, `REPORT-*`, `AUDIT-*`, and
1792
+ destructive snapshot; Evolve handoffs own their `RESEARCH-*` digest. The
1793
+ retention daemon keeps active/retryable work, recovery material, and endorsed
1794
+ but unapplied reports. After both enabled workflow bounds expire, it first
1795
+ compacts batch/research bodies to a SHA-256 plus a 512-character summary and
1796
+ removes only owned files. A later pass removes the compacted rows. File removal
1797
+ is path-contained to the configured Curator or Evolve directory, rejects
1798
+ symlinks, and is journaled so an interrupted delete retries safely. Use
1799
+ `workflow_retention_preview()` for the dry-run counts/bytes and oldest terminal
1800
+ pass; `mp_dashboard()` shows its latest outcome. A selective `forget()` that
1801
+ matches a frozen workflow body compacts it immediately, including active work;
1802
+ the normal report/lesson review guidance still applies to generalized content.
1803
+
1705
1804
  `db_compact()` is the opt-in disk-reclaim tool: `VACUUM` + a mandatory
1706
1805
  `dialog_fts` rebuild (schema v2 keys the FTS index on `dialog_messages`
1707
1806
  rowids, which `VACUUM` is permitted to renumber — the rebuild is what
@@ -1868,9 +1967,9 @@ reusable verdict logic lives in `threadkeeper/verify_ingest.py`.
1868
1967
  ## Memory-quality evaluation
1869
1968
 
1870
1969
  The ingest verifier above answers *"did we capture the data?"*. The
1871
- memory-quality harness answers the harder question — *"when we retrieve it,
1872
- do we recall the right fact, and do we **refuse** to answer about things that
1873
- never happened?"* It's modeled on
1970
+ memory-quality harness answers two separate questions: *"did we retrieve the
1971
+ right evidence?"* and *"does an agent produce the right final answer from
1972
+ that evidence?"* It's modeled on
1874
1973
  [LongMemEval](https://arxiv.org/pdf/2410.10813) (ICLR 2025) plus mem0's 2026
1875
1974
  [tokens-per-retrieval](https://mem0.ai/blog/ai-memory-benchmarks-in-2026)
1876
1975
  cost axis, and runs the **real** `search()` / `dialog_search()` / `brief()`
@@ -1881,24 +1980,34 @@ python scripts/memory_eval/run.py # bundled demo corpus, lexical
1881
1980
  python scripts/memory_eval/run.py --json # machine-readable report
1882
1981
  python scripts/memory_eval/run.py --db snap.sqlite --ground-truth my_labels.json
1883
1982
  python scripts/memory_eval/run.py --semantic # use embeddings if installed
1884
- python scripts/memory_eval/run.py --judge llm # LLM-graded (needs ANTHROPIC_API_KEY)
1983
+ python scripts/memory_eval/run.py --matrix --strict # FTS/hybrid migration gate
1984
+ age -d holdout.json.age | python scripts/memory_eval/run.py \
1985
+ --ground-truth /dev/stdin --private-holdout # no per-case output
1885
1986
  ```
1886
1987
 
1887
- It reports four headline groups over a fixed ground-truth set:
1988
+ It reports these headline groups over a fixed ground-truth set:
1888
1989
 
1889
- - **accuracy** — fraction of questions whose retrieval recalled the gold
1890
- fact, broken out per the five LongMemEval axes (information extraction,
1891
- multi-session reasoning, temporal reasoning, knowledge updates, abstention).
1990
+ - **evidence recall** and **final-answer correctness** — separate scores, both
1991
+ per axis. The final answer comes from a deterministic replay responder that
1992
+ may emit only facts found in the returned context; it gives CI a stable
1993
+ boundary between retrieval and reasoning failures.
1892
1994
  - **abstention rate** — of the *never-happened* questions, the fraction the
1893
- system correctly refused. This is the highest-payoff axis: it directly
1894
- measures whether the auto-injected `brief()` context fabricates or surfaces
1895
- stale facts.
1995
+ system correctly refused. Retention/curation removals and egress-blocked
1996
+ personal memory are also required to end in a refusal.
1896
1997
  - **tokens-per-retrieval** — mean / median / max tokens of what each query
1897
- returned, so recall is never read apart from cost (a wider window that
1898
- recalls more also costs more).
1998
+ returned, plus equivalent final-answer token totals.
1899
1999
  - **retrieval latency** — mean / p50 / p95 / max wall-clock milliseconds. With
1900
2000
  `--semantic`, the backend is reported as `hybrid`, because dense candidates
1901
2001
  augment rather than replace FTS.
2002
+ - **outcome classification** — retrieval failure, reasoning failure,
2003
+ stale-memory use, removed-memory use, and privacy-policy violation.
2004
+
2005
+ `--matrix` runs every public-fixture case through the FTS and hybrid backends,
2006
+ three fixture states (`baseline`, `retained`, `curated`), and every personal
2007
+ memory egress policy (`all`, `same-vendor`, `work-only`). A hybrid row is marked
2008
+ unavailable when the optional semantic extra is not installed. `--strict`
2009
+ requires the versioned fixture thresholds and zero safety violations, making
2010
+ the same command suitable for retrieval/model migration gates.
1902
2011
 
1903
2012
  For DB concurrency, run the reproducible local gate:
1904
2013
 
@@ -1910,18 +2019,20 @@ The JSON result includes expected/actual writes, throughput, p50/p95/p99/max
1910
2019
  write latency, worker errors, elapsed time, and `PRAGMA quick_check`; a non-zero
1911
2020
  exit means a lost write, worker failure, or integrity failure.
1912
2021
 
1913
- With no `--db` the harness builds the bundled fixture
1914
- (`scripts/memory_eval/ground_truth.json` — a fictional "billing service" told
1915
- across three sessions) into a throwaway DB; it's a **golden baseline** where a
1916
- faithful retrieval scores 100%, so a regression in the retrieval tools drops
1917
- the number. `--db` runs **read-only**: the snapshot is copied to a temp file
1918
- and the original is never opened for writing. The default judge is **lexical**
1919
- (deterministic, offline, no API key, no embeddings) so the command is
1920
- reproducible and CI-safe; `--judge llm` grades answer *reasoning* (not just
1921
- retrieval recall) with an Anthropic model when a key is set — the intended
1922
- optimization target for lesson-decay tuning (#27) and bi-temporal claims (#28)
1923
- work. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for how the
1924
- axes map onto thread-keeper's retrieval surface.
2022
+ With no `--db` the harness builds the bundled, versioned public synthetic
2023
+ fixture (`scripts/memory_eval/ground_truth.json` — a fictional "billing
2024
+ service") into a throwaway DB. Bump its `version` whenever cases, labels, or
2025
+ thresholds change; CI uses the checked-in version and its stable thresholds.
2026
+ `--db` runs **read-only**: the snapshot is copied to a temp file and the
2027
+ original is never opened for writing.
2028
+
2029
+ For a private holdout, keep the corpus encrypted or outside the repository and
2030
+ pass it with `--private-holdout`. The runner does not decrypt data itself; it
2031
+ accepts a locally decrypted file or stdin and deletes its temporary DB on exit.
2032
+ Private mode emits aggregate metrics only — no case rows, failure details,
2033
+ retrieved context, or replayed answer is written to stdout, artifacts, or the
2034
+ repository. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the corpus
2035
+ contract and migration-gate interpretation.
1925
2036
 
1926
2037
  ## Evaluating learning-loop decision quality
1927
2038
 
@@ -2023,7 +2134,9 @@ threadkeeper/
2023
2134
  so `tools/list` carries MCP 2025-06-18 `ToolAnnotations` for every
2024
2135
  registered tool: `readOnlyHint=True` for pure reads (`brief`, `context`, `search`,
2025
2136
  `dialog_search`, the status tools, …) and `readOnlyHint=False`
2026
- for mutations. `lesson_list` / `lesson_get` are classified as non-destructive
2137
+ for mutations. Advertised reads use query-only database connections and never
2138
+ bootstrap a session, start daemon work, refresh process data, or mutate
2139
+ lifecycle state. `lesson_list` / `lesson_get` are classified as non-destructive
2027
2140
  writes because they bump lesson access counters. Delete/overwrite/kill tools
2028
2141
  carry `destructiveHint=True` (`compost` is read-only — it only surfaces idle
2029
2142
  threads). A confirmation/elicitation host reads this to decide which calls
@@ -2038,6 +2151,15 @@ capability before prompting, uses only a flat primitive schema, and leaves
2038
2151
  unsupported clients on the existing text/tool fallback path. The first protected
2039
2152
  write is `dialectic_supersede`.
2040
2153
 
2154
+ **Protocol compatibility (#344).** The stdio server supports the
2155
+ `2025-11-25` initialize-handshake era and the `2026-07-28` request-envelope
2156
+ era. Legacy hosts retain the existing tools, resources, and prompts. Modern
2157
+ calls derive identity and capabilities from every request, static discovery
2158
+ catalogs advertise public cache freshness, and replaying a completed write with
2159
+ the same caller-bound JSON-RPC id returns the original result instead of
2160
+ committing a second mutation. Sealed continuation state expires after five
2161
+ minutes; an interrupted write with no terminal result is rejected on replay.
2162
+
2041
2163
  Detailed map in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
2042
2164
  Open work in [docs/ROADMAP.md](docs/ROADMAP.md) and the
2043
2165
  [Issues tab](https://github.com/po4erk91/thread-keeper/issues).