zettelforge 2.5.1__tar.gz → 2.6.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 (360) hide show
  1. zettelforge-2.6.2/.github/workflows/stale.yml +47 -0
  2. {zettelforge-2.5.1 → zettelforge-2.6.2}/.gitignore +13 -0
  3. {zettelforge-2.5.1 → zettelforge-2.6.2}/CHANGELOG.md +187 -0
  4. {zettelforge-2.5.1 → zettelforge-2.6.2}/CONTRIBUTING.md +43 -0
  5. zettelforge-2.6.2/CONTRIBUTORS.md +17 -0
  6. {zettelforge-2.5.1 → zettelforge-2.6.2}/PKG-INFO +9 -2
  7. {zettelforge-2.5.1 → zettelforge-2.6.2}/README.md +2 -1
  8. zettelforge-2.6.2/ROADMAP.md +94 -0
  9. {zettelforge-2.5.1 → zettelforge-2.6.2}/config.default.yaml +56 -2
  10. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/THREAT_MODEL.md +7 -5
  11. zettelforge-2.6.2/docs/explanation/llm-budgets-and-timeouts.md +101 -0
  12. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/troubleshoot.md +99 -8
  13. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/upgrade.md +67 -3
  14. zettelforge-2.6.2/docs/how-to/use-web-interface.md +177 -0
  15. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/index.md +4 -2
  16. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/reference/configuration.md +111 -6
  17. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/reference/module-inventory.md +40 -1
  18. zettelforge-2.6.2/docs/reference/web-api.md +415 -0
  19. zettelforge-2.6.2/docs/rfcs/RFC-014-content-limits.md +143 -0
  20. zettelforge-2.6.2/docs/rfcs/RFC-015-zettelforge-web-gui.md +624 -0
  21. {zettelforge-2.5.1 → zettelforge-2.6.2}/mkdocs.yml +1 -0
  22. zettelforge-2.6.2/pr-body.md +41 -0
  23. {zettelforge-2.5.1 → zettelforge-2.6.2}/pyproject.toml +9 -1
  24. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/__init__.py +1 -1
  25. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/config.py +60 -1
  26. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/entity_indexer.py +5 -2
  27. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/fact_extractor.py +3 -1
  28. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/governance_validator.py +17 -1
  29. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/lance_maintenance.py +8 -8
  30. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_providers/ollama_provider.py +1 -1
  31. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/memory_evolver.py +2 -2
  32. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/memory_manager.py +60 -0
  33. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/note_constructor.py +9 -1
  34. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/synthesis_generator.py +5 -1
  35. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_config.py +27 -0
  36. zettelforge-2.6.2/tests/test_governance.py +125 -0
  37. zettelforge-2.6.2/tests/test_web_api.py +493 -0
  38. zettelforge-2.6.2/web/app.py +1005 -0
  39. zettelforge-2.6.2/web/static/css/design_tokens.css +114 -0
  40. zettelforge-2.6.2/web/templates/base.html +201 -0
  41. zettelforge-2.6.2/web/templates/components/remember_panel.html +72 -0
  42. zettelforge-2.6.2/web/templates/components/result_card.html +98 -0
  43. zettelforge-2.6.2/web/templates/components/search_bar.html +11 -0
  44. zettelforge-2.6.2/web/templates/components/synthesis_block.html +58 -0
  45. zettelforge-2.6.2/web/templates/components/tab_bar.html +42 -0
  46. zettelforge-2.6.2/web/templates/config_editor.html +799 -0
  47. zettelforge-2.6.2/web/templates/index.html +279 -0
  48. zettelforge-2.6.2/web/ui/assets/favicon-16.png +0 -0
  49. zettelforge-2.6.2/web/ui/assets/favicon-32.png +0 -0
  50. zettelforge-2.6.2/web/ui/assets/favicon-512.png +0 -0
  51. zettelforge-2.6.2/web/ui/assets/favicon-apple-touch.png +0 -0
  52. zettelforge-2.6.2/web/ui/assets/logo.svg +42 -0
  53. zettelforge-2.6.2/web/ui/assets/threatrecall-lockup.svg +39 -0
  54. zettelforge-2.6.2/web/ui/assets/zettelforge_architecture.svg +104 -0
  55. zettelforge-2.6.2/web/ui/colors_and_type.css +286 -0
  56. zettelforge-2.6.2/web/ui/favicon.svg +33 -0
  57. zettelforge-2.6.2/web/ui/fonts/Neuropol.otf +0 -0
  58. zettelforge-2.6.2/web/ui/index.html +55 -0
  59. zettelforge-2.6.2/web/ui/js/app.js +144 -0
  60. zettelforge-2.6.2/web/ui/js/components/header.js +95 -0
  61. zettelforge-2.6.2/web/ui/js/components/result-card.js +69 -0
  62. zettelforge-2.6.2/web/ui/js/components/sidebar.js +57 -0
  63. zettelforge-2.6.2/web/ui/js/components/spinner.js +8 -0
  64. zettelforge-2.6.2/web/ui/js/components/tabs.js +17 -0
  65. zettelforge-2.6.2/web/ui/js/components/toast.js +35 -0
  66. zettelforge-2.6.2/web/ui/js/lib/api.js +83 -0
  67. zettelforge-2.6.2/web/ui/js/lib/state.js +50 -0
  68. zettelforge-2.6.2/web/ui/js/views/configuration.js +784 -0
  69. zettelforge-2.6.2/web/ui/js/views/dashboard.js +251 -0
  70. zettelforge-2.6.2/web/ui/js/views/entities.js +415 -0
  71. zettelforge-2.6.2/web/ui/js/views/history.js +296 -0
  72. zettelforge-2.6.2/web/ui/js/views/ingest.js +425 -0
  73. zettelforge-2.6.2/web/ui/js/views/knowledge-graph.js +606 -0
  74. zettelforge-2.6.2/web/ui/js/views/logs.js +256 -0
  75. zettelforge-2.6.2/web/ui/js/views/search.js +343 -0
  76. zettelforge-2.5.1/docs/superpowers/research/2026-04-09-ctibench-ragas-benchmarks.md +0 -31
  77. zettelforge-2.5.1/docs/superpowers/research/2026-04-09-fastembed-local-embeddings.md +0 -460
  78. zettelforge-2.5.1/docs/superpowers/research/2026-04-09-hybrid-typedb-lancedb-architecture.md +0 -855
  79. zettelforge-2.5.1/docs/superpowers/research/2026-04-09-local-llm-llama-cpp.md +0 -17
  80. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-anti-aversion-cleanup.md +0 -763
  81. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-causal-graph.md +0 -409
  82. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-ctibench-ate-fix.md +0 -211
  83. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-format-stability.md +0 -1029
  84. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-memory-evolution.md +0 -428
  85. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-merge-consolidation.md +0 -372
  86. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-persistence-semantics.md +0 -422
  87. zettelforge-2.5.1/docs/superpowers/research/2026-04-15-sqlite-migration.md +0 -636
  88. zettelforge-2.5.1/docs/superpowers/research/2026-04-17-test-suite-audit.md +0 -178
  89. zettelforge-2.5.1/docs/superpowers/research/2026-04-24-phase-0.5-attribution-prelim.md +0 -123
  90. zettelforge-2.5.1/docs/superpowers/research/2026-04-25-graph-retriever-silence.md +0 -117
  91. zettelforge-2.5.1/docs/superpowers/research/2026-04-25-phase-0.5-attribution.md +0 -230
  92. zettelforge-2.5.1/docs/superpowers/research/README.md +0 -40
  93. zettelforge-2.5.1/docs/superpowers/specs/2026-04-15-p1-features-prd.md +0 -990
  94. zettelforge-2.5.1/tests/test_governance.py +0 -32
  95. zettelforge-2.5.1/web/app.py +0 -530
  96. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/CODEOWNERS +0 -0
  97. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  98. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  99. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/SECURITY.md +0 -0
  100. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/dependabot.yml +0 -0
  101. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/pull_request_template.md +0 -0
  102. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/workflows/ci.yml +0 -0
  103. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/workflows/docs.yml +0 -0
  104. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/workflows/publish.yml +0 -0
  105. {zettelforge-2.5.1 → zettelforge-2.6.2}/.github/workflows/snyk-security.yml +0 -0
  106. {zettelforge-2.5.1 → zettelforge-2.6.2}/ARCHITECTURE.md +0 -0
  107. {zettelforge-2.5.1 → zettelforge-2.6.2}/CODEOWNERS +0 -0
  108. {zettelforge-2.5.1 → zettelforge-2.6.2}/CODE_OF_CONDUCT.md +0 -0
  109. {zettelforge-2.5.1 → zettelforge-2.6.2}/Dockerfile +0 -0
  110. {zettelforge-2.5.1 → zettelforge-2.6.2}/GOVERNANCE.md +0 -0
  111. {zettelforge-2.5.1 → zettelforge-2.6.2}/LICENSE +0 -0
  112. {zettelforge-2.5.1 → zettelforge-2.6.2}/MANIFEST.in +0 -0
  113. {zettelforge-2.5.1 → zettelforge-2.6.2}/SECURITY.md +0 -0
  114. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/BENCHMARK_REPORT.md +0 -0
  115. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
  116. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/auto_ralph.py +0 -0
  117. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/benchmark_harness.py +0 -0
  118. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/cti_benchmark_v2.py +0 -0
  119. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/cti_retrieval_benchmark.py +0 -0
  120. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/cti_retrieval_results.json +0 -0
  121. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/cti_v2_results.json +0 -0
  122. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/ctibench_benchmark.py +0 -0
  123. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/ctibench_results.json +0 -0
  124. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/dataset.json +0 -0
  125. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/enterprise-attack.json +0 -0
  126. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/evolve_benchmark.py +0 -0
  127. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/evolve_results.json +0 -0
  128. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/graph_test.py +0 -0
  129. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/locomo_benchmark.py +0 -0
  130. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/locomo_results.json +0 -0
  131. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
  132. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/memoryagentbench.py +0 -0
  133. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/memoryagentbench_results.json +0 -0
  134. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/mempalace_benchmark.py +0 -0
  135. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/mempalace_results.json +0 -0
  136. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/naive_memory.py +0 -0
  137. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/opencti_benchmark.py +0 -0
  138. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/ragas_benchmark.py +0 -0
  139. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/ragas_cti_results.json +0 -0
  140. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/ragas_results.json +0 -0
  141. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/results/benchmark_report.md +0 -0
  142. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/results/ralph_optimization_log.json +0 -0
  143. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/scale_benchmark.py +0 -0
  144. {zettelforge-2.5.1 → zettelforge-2.6.2}/benchmarks/scale_results.json +0 -0
  145. {zettelforge-2.5.1 → zettelforge-2.6.2}/config.example.yaml +0 -0
  146. {zettelforge-2.5.1 → zettelforge-2.6.2}/docker/docker-compose.yml +0 -0
  147. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/.well-known/security.txt +0 -0
  148. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/CNAME +0 -0
  149. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/architecture-diagram.mmd +0 -0
  150. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/archive/PACKAGE_SUMMARY.md +0 -0
  151. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/archive/README.md +0 -0
  152. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/archive/SKILL.md +0 -0
  153. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/ZettelForge_Architecture.mmd +0 -0
  154. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/architecture-overview.mmd +0 -0
  155. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/architecture-read-path.mmd +0 -0
  156. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/architecture-write-path.mmd +0 -0
  157. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/cf-analytics.js +0 -0
  158. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/demo.gif +0 -0
  159. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/favicon-16.png +0 -0
  160. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/favicon-32.png +0 -0
  161. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/favicon-512.png +0 -0
  162. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/favicon-64.png +0 -0
  163. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/favicon-apple-touch.png +0 -0
  164. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/favicon-old.svg +0 -0
  165. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/favicon.svg +0 -0
  166. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/logo.svg +0 -0
  167. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/social-preview.png +0 -0
  168. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/threatrecall-lockup-monogram.svg +0 -0
  169. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/threatrecall-lockup.svg +0 -0
  170. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/threatrecall-logo-flat.svg +0 -0
  171. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/threatrecall-logo-philosophy.md +0 -0
  172. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/threatrecall-logo.png +0 -0
  173. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/threatrecall-mark.png +0 -0
  174. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/zettelforge_architecture-light.svg +0 -0
  175. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/assets/zettelforge_architecture.svg +0 -0
  176. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/brand/brandIdentity.md +0 -0
  177. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/brand/colors_and_type.css +0 -0
  178. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/explanation/architecture.md +0 -0
  179. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/explanation/epistemic-tiers.md +0 -0
  180. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/explanation/stix-in-zettelforge.md +0 -0
  181. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/explanation/two-phase-pipeline.md +0 -0
  182. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/explanation/zettelkasten-philosophy.md +0 -0
  183. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/configure-lancedb.md +0 -0
  184. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/configure-opencti.md +0 -0
  185. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/configure-pii.md +0 -0
  186. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/configure-typedb.md +0 -0
  187. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/ingest-news-report.md +0 -0
  188. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/integrate-llm-agent.md +0 -0
  189. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/migrate-jsonl-to-sqlite.md +0 -0
  190. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/query-apt-tools.md +0 -0
  191. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/reproduce-benchmarks.md +0 -0
  192. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/resolve-aliases.md +0 -0
  193. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/run-temporal-query.md +0 -0
  194. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/how-to/store-threat-actor.md +0 -0
  195. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/human-evaluation-rubric.md +0 -0
  196. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/llms.txt +0 -0
  197. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/narrative/2026-04-16-the-memory-problem.md +0 -0
  198. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/overrides/main.html +0 -0
  199. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/reference/architecture-deep-dive.md +0 -0
  200. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/reference/governance-controls.md +0 -0
  201. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/reference/memory-manager-api.md +0 -0
  202. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/reference/retrieval-policies.md +0 -0
  203. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/reference/stix-schema.md +0 -0
  204. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -0
  205. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-002-universal-llm-provider.md +0 -0
  206. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-003-adversarial-review.md +0 -0
  207. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-003-read-path-depth-routing.md +0 -0
  208. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-007-operational-telemetry.md +0 -0
  209. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-009-enrichment-pipeline-v2.md +0 -0
  210. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-010-enrichment-hotfix.md +0 -0
  211. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-011-local-llm-backend-config.md +0 -0
  212. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-012-litellm-unified-provider.md +0 -0
  213. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/rfcs/RFC-013-presidio-pii-detection.md +0 -0
  214. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/stylesheets/brand-tokens.css +0 -0
  215. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/stylesheets/extra.css +0 -0
  216. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/stylesheets/fonts/Neuropol.otf +0 -0
  217. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/tutorials/01-quickstart.md +0 -0
  218. {zettelforge-2.5.1 → zettelforge-2.6.2}/docs/tutorials/02-first-cti-report.md +0 -0
  219. {zettelforge-2.5.1 → zettelforge-2.6.2}/examples/athf_bridge.py +0 -0
  220. {zettelforge-2.5.1 → zettelforge-2.6.2}/examples/mcp_claude_code.md +0 -0
  221. {zettelforge-2.5.1 → zettelforge-2.6.2}/examples/quickstart.py +0 -0
  222. {zettelforge-2.5.1 → zettelforge-2.6.2}/governance/controls.yaml +0 -0
  223. {zettelforge-2.5.1 → zettelforge-2.6.2}/scripts/migrate_jsonl_to_sqlite.py +0 -0
  224. {zettelforge-2.5.1 → zettelforge-2.6.2}/scripts/rebuild_index.py +0 -0
  225. {zettelforge-2.5.1 → zettelforge-2.6.2}/scripts/record-demo.sh +0 -0
  226. {zettelforge-2.5.1 → zettelforge-2.6.2}/scripts/typedb-setup.sh +0 -0
  227. {zettelforge-2.5.1 → zettelforge-2.6.2}/scripts/zettelforge-rebuild.service +0 -0
  228. {zettelforge-2.5.1 → zettelforge-2.6.2}/scripts/zettelforge-rebuild.timer +0 -0
  229. {zettelforge-2.5.1 → zettelforge-2.6.2}/server.json +0 -0
  230. {zettelforge-2.5.1 → zettelforge-2.6.2}/skills/claude-code-skill.md +0 -0
  231. {zettelforge-2.5.1 → zettelforge-2.6.2}/skills/openclaw-skill.md +0 -0
  232. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/__main__.py +0 -0
  233. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/alias_resolver.py +0 -0
  234. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/backend_factory.py +0 -0
  235. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/blended_retriever.py +0 -0
  236. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/cache.py +0 -0
  237. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/consolidation.py +0 -0
  238. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/demo.py +0 -0
  239. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/detection/__init__.py +0 -0
  240. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/detection/base.py +0 -0
  241. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/detection/consumers.py +0 -0
  242. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/detection/explainer.py +0 -0
  243. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/edition.py +0 -0
  244. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/extensions.py +0 -0
  245. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/graph_retriever.py +0 -0
  246. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/integrations/__init__.py +0 -0
  247. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/integrations/langchain_retriever.py +0 -0
  248. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/intent_classifier.py +0 -0
  249. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/json_parse.py +0 -0
  250. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/knowledge_graph.py +0 -0
  251. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_client.py +0 -0
  252. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_providers/__init__.py +0 -0
  253. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_providers/base.py +0 -0
  254. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_providers/litellm_provider.py +0 -0
  255. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_providers/local_provider.py +0 -0
  256. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_providers/mock_provider.py +0 -0
  257. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/llm_providers/registry.py +0 -0
  258. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/log.py +0 -0
  259. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/mcp/__init__.py +0 -0
  260. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/mcp/__main__.py +0 -0
  261. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/mcp/server.py +0 -0
  262. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/memory_store.py +0 -0
  263. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/memory_updater.py +0 -0
  264. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/note_schema.py +0 -0
  265. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/observability.py +0 -0
  266. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/ocsf.py +0 -0
  267. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/ontology.py +0 -0
  268. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/pii_validator.py +0 -0
  269. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/retry.py +0 -0
  270. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/scripts/compact_lance.py +0 -0
  271. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/scripts/human_eval_sampler.py +0 -0
  272. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/scripts/telemetry_aggregator.py +0 -0
  273. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/scripts/telemetry_dashboard.py +0 -0
  274. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/__init__.py +0 -0
  275. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/cli.py +0 -0
  276. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/entities.py +0 -0
  277. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/ingest.py +0 -0
  278. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/parser.py +0 -0
  279. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/schemas/NOTICE.md +0 -0
  280. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/schemas/__init__.py +0 -0
  281. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +0 -0
  282. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +0 -0
  283. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/schemas/sigma-filters-schema.json +0 -0
  284. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sigma/tags.py +0 -0
  285. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/sqlite_backend.py +0 -0
  286. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/storage_backend.py +0 -0
  287. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/synthesis_validator.py +0 -0
  288. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/telemetry.py +0 -0
  289. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/vector_memory.py +0 -0
  290. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/vector_retriever.py +0 -0
  291. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/__init__.py +0 -0
  292. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/cccs_metadata.py +0 -0
  293. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/cli.py +0 -0
  294. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/entities.py +0 -0
  295. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/ingest.py +0 -0
  296. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/parser.py +0 -0
  297. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/schemas/CCCS_YARA.yml +0 -0
  298. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +0 -0
  299. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/schemas/NOTICE.md +0 -0
  300. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/schemas/__init__.py +0 -0
  301. {zettelforge-2.5.1 → zettelforge-2.6.2}/src/zettelforge/yara/tags.py +0 -0
  302. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/__init__.py +0 -0
  303. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/benchmark_scale.py +0 -0
  304. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/conftest.py +0 -0
  305. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/fixtures/sigma/cloud_example.yml +0 -0
  306. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/fixtures/sigma/correlation_example.yml +0 -0
  307. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/fixtures/sigma/process_creation_example.yml +0 -0
  308. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/fixtures/sigma/tagged_example.yml +0 -0
  309. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/fixtures/yara/malware_hash.yar +0 -0
  310. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/fixtures/yara/technique_loader.yar +0 -0
  311. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/fixtures/yara/webshell.yar +0 -0
  312. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_basic.py +0 -0
  313. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_blended_retriever.py +0 -0
  314. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_causal_extraction.py +0 -0
  315. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_consolidation.py +0 -0
  316. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_conversational_entities.py +0 -0
  317. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_core.py +0 -0
  318. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_cti_integration.py +0 -0
  319. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_detection_explainer.py +0 -0
  320. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_detection_rule_entities.py +0 -0
  321. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_edition.py +0 -0
  322. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_embedding.py +0 -0
  323. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_entity_indexer_races.py +0 -0
  324. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_extensions.py +0 -0
  325. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_fact_extractor.py +0 -0
  326. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_governance_spec_drift.py +0 -0
  327. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_graph_retriever.py +0 -0
  328. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_human_eval_sampler.py +0 -0
  329. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_intent_classifier.py +0 -0
  330. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_json_parse.py +0 -0
  331. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_kg_edge_schema.py +0 -0
  332. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_lance_maintenance.py +0 -0
  333. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_langchain_retriever.py +0 -0
  334. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_llm_client.py +0 -0
  335. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_llm_providers.py +0 -0
  336. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_logging_compliance.py +0 -0
  337. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_mcp_server.py +0 -0
  338. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_memory_evolver.py +0 -0
  339. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_memory_updater.py +0 -0
  340. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_performance.py +0 -0
  341. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_pii_validator.py +0 -0
  342. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_recall_integration.py +0 -0
  343. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_sigma_entities.py +0 -0
  344. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_sigma_ingest.py +0 -0
  345. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_sigma_parser.py +0 -0
  346. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_sqlite_backend.py +0 -0
  347. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_sqlite_integration.py +0 -0
  348. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_storage_backend.py +0 -0
  349. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_telemetry_aggregator.py +0 -0
  350. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_telemetry_collector.py +0 -0
  351. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_telemetry_dashboard.py +0 -0
  352. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_telemetry_integration.py +0 -0
  353. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_temporal_graph.py +0 -0
  354. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_two_phase_e2e.py +0 -0
  355. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_typedb_client.py +0 -0
  356. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_yara_entities.py +0 -0
  357. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_yara_ingest.py +0 -0
  358. {zettelforge-2.5.1 → zettelforge-2.6.2}/tests/test_yara_parser.py +0 -0
  359. {zettelforge-2.5.1 → zettelforge-2.6.2}/web/auth.py +0 -0
  360. {zettelforge-2.5.1 → zettelforge-2.6.2}/web/mcp_server.py +0 -0
@@ -0,0 +1,47 @@
1
+ name: Stale issue and PR management
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 9 * * 1" # Every Monday at 09:00 UTC
6
+
7
+ permissions:
8
+ issues: write
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ stale:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/stale@v9
16
+ with:
17
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
18
+
19
+ # Issues
20
+ stale-issue-message: >
21
+ This issue has been inactive for 60 days. It will be closed
22
+ in 14 days unless there is new activity. If this is still
23
+ relevant, please comment to keep it open.
24
+ close-issue-message: >
25
+ This issue has been automatically closed after 14 days of
26
+ inactivity. It can be reopened at any time.
27
+ days-before-issue-stale: 60
28
+ days-before-issue-close: 14
29
+ stale-issue-label: stale
30
+ exempt-issue-labels: "p0,planned,help wanted,good first issue"
31
+
32
+ # PRs
33
+ stale-pr-message: >
34
+ This pull request has been inactive for 60 days. It will be
35
+ closed in 14 days unless there is new activity.
36
+ close-pr-message: >
37
+ This pull request has been automatically closed after 14 days
38
+ of inactivity.
39
+ days-before-pr-stale: 60
40
+ days-before-pr-close: 14
41
+ stale-pr-label: stale
42
+ exempt-pr-labels: "draft,work-in-progress"
43
+
44
+ # General
45
+ operations-per-run: 100
46
+ remove-stale-when-updated: true
47
+ delete-branch: false
@@ -12,6 +12,17 @@ tasks/
12
12
  docs/.ralph/
13
13
  agentsync.md
14
14
 
15
+ # Internal research/specs/plans — workspace scratch that contains
16
+ # unredacted incident detail, customer references, and intermediate
17
+ # reasoning. Kept on disk for the maintainer; not published.
18
+ docs/superpowers/
19
+
20
+ # Claude Code session artifacts — agent worktrees, transcripts, and
21
+ # scratch state created by the maintainer's local tooling. Belt-and-
22
+ # suspenders: these were never tracked, but listing them prevents an
23
+ # accidental `git add -A` from sweeping them in.
24
+ .claude/
25
+
15
26
  # MkDocs build output (regenerated from docs/)
16
27
  site/
17
28
 
@@ -28,6 +39,8 @@ downloads/
28
39
  eggs/
29
40
  .eggs/
30
41
  lib/
42
+ !web/ui/js/lib/
43
+ !web/ui/js/lib/*.js
31
44
  lib64/
32
45
  parts/
33
46
  sdist/
@@ -6,6 +6,193 @@ Versioning follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.6.2] - 2026-04-27
10
+
11
+ UI/UX release. Fixes the `/config` page so the Apply button actually works
12
+ and surfaces enum-style settings as dropdowns instead of free-text inputs.
13
+ No data migration. No config changes. No API contract changes.
14
+
15
+ ### Fixed
16
+
17
+ - **`/config` "Save Changes" button is no longer dead.** The Quick Settings
18
+ panel called `saveConfigForm()` and `reloadConfig()` — neither function
19
+ was defined anywhere, so the button silently no-op'd and the panel
20
+ rendered "Loading schema..." forever. Replaced with a real form-based
21
+ editor whose Apply button PUTs a nested payload to `/api/config` and
22
+ reloads from server on success.
23
+
24
+ ### Added
25
+
26
+ - **Form-based config editor with dropdowns.** `/config` now renders a
27
+ grouped settings form alongside the YAML editor. Known enum fields
28
+ (`backend`, `embedding.provider`, `llm.provider`, `llm.local_backend`,
29
+ `logging.level`, `synthesis.default_format`, `governance.pii.action`)
30
+ render as `<select>` controls instead of free-text inputs. Restart-
31
+ required leaves get a "restart required" badge sourced from the same
32
+ set the server uses, so the UI warning is never out of sync with the
33
+ server's classification.
34
+ - **Pending-changes counter and Revert button.** The form tracks dirty
35
+ fields by dotted path, builds a single nested payload on Apply, and
36
+ shows `N pending change(s) (M need restart)` next to the buttons.
37
+ - **YAML editor accepts both YAML and JSON** (was JSON-only despite the
38
+ label) and skips redacted `***` secrets so they aren't PUT back as
39
+ literal strings.
40
+
41
+ ### Tests
42
+
43
+ - 4 new tests in `tests/test_web_api.py`: dropdown enum round-trip for
44
+ `logging.level` (restart-required) and `synthesis.default_format` (live);
45
+ multi-section nested payload from a single Apply; and a regression guard
46
+ on the `/config` HTML structure (form tab, dropdown enum declarations,
47
+ restart-leaf flags, and proof the dead `saveConfigForm`/`reloadConfig`
48
+ handlers are gone). 28 passed, 2 skipped (was 24 + 2).
49
+
50
+ ## [2.6.1] - 2026-04-25
51
+
52
+ Hotfix release. Resolves three blockers found in code review of the
53
+ RFC-015 web GUI shipped in v2.6.0. No data migration. No config changes.
54
+
55
+ ### Fixed
56
+
57
+ - **`/config` HTML page now renders.** `_to_dict` was defined as a closure
58
+ inside `get_config_endpoint`, so every render of `/config` raised
59
+ `NameError`, was silently swallowed by a bare `except`, and left the
60
+ YAML body blank on initial server-side render. Promoted to a module-level
61
+ `_config_to_dict` helper used by both routes. (PR #131)
62
+ - **`PUT /api/config` correctly reports nested restart-required fields.**
63
+ The check compared top-level payload keys against a set of dotted-path
64
+ fields, so payloads like `{"embedding": {"provider": "x"}}` were
65
+ reported as `applied: ["embedding"]`, `pending_restart: []`, telling
66
+ operators a restart-required change had taken effect when it had not.
67
+ Added `_flatten_keys` to walk nested payloads to dotted leaf paths;
68
+ `applied` and `pending_restart` now contain accurate dotted paths.
69
+ (PR #131)
70
+ - **`/config` HTML route is now auth-gated.** `/api/config` was protected,
71
+ but the HTML shell (and once the `_to_dict` bug was fixed, its
72
+ server-rendered YAML body) was reachable without an API key. Added
73
+ `Depends(require_api_guard)` and made the YAML body redact secrets
74
+ before serialization. (PR #131)
75
+
76
+ ### Tests
77
+
78
+ - Added four regression tests in `tests/test_web_api.py` covering all
79
+ three fixes. 24 passed, 2 skipped (was 20 + 2).
80
+
81
+ ## [2.6.0] - 2026-04-25
82
+
83
+ Feature release. Adds configurable content-size limits for DoS mitigation
84
+ (RFC-014) and moves per-call-site LLM token budgets out of hardcoded
85
+ literals into `LLMConfig`, making them overridable at deploy time.
86
+
87
+ ### Added
88
+
89
+ - **Configurable content size limits** (`GovernanceConfig.limits.max_content_length`,
90
+ default 50 MB). `remember()` calls with content exceeding the limit are
91
+ rejected with a clear error message. Set to `0` to disable the check.
92
+ Environment override: `ZETTELFORGE_LIMITS_MAX_CONTENT_LENGTH`.
93
+ (RFC-014, PR #123)
94
+ - **Per-call-site `max_tokens` budgets configurable via `LLMConfig`**.
95
+ Five new fields: `max_tokens_causal` (8000), `max_tokens_synthesis` (2500),
96
+ `max_tokens_fact` (2500), `max_tokens_ner` (2500), `max_tokens_evolution` (2500).
97
+ Defaults match v2.5.2 values. No behavioral change for existing configs.
98
+ (PR #126, issue #125)
99
+
100
+ ### Changed
101
+
102
+ - **Docs: config reconciliation for v2.5.2** — `config.default.yaml` gained
103
+ the `lance:` section (RFC-009 Phase 1.5), `docs/reference/configuration.md`
104
+ now covers all v2.5.2 knobs (`lance`, `pii`, per-call-site budgets), and
105
+ `docs/explanation/llm-budgets-and-timeouts.md` explains the reasoning-model
106
+ token-budget tradeoffs. (PR #126)
107
+ - **`_apply_yaml()` now handles `lance:` section** — previously the
108
+ `lance.cleanup_interval_minutes` and `lance.cleanup_older_than_seconds` YAML
109
+ knobs were silently ignored (regression from RFC-009 Phase 1.5 landing in
110
+ v2.4.x without the `_apply_yaml` branch). (PR #126, code review finding)
111
+
112
+ ### Internal
113
+
114
+ - **Removed `docs/superpowers/` from version control**. The directory holds
115
+ workspace scratch — internal research and notes with unredacted incident
116
+ detail. 18 files (7319 lines) untracked. No published content lost.
117
+ (PR #128)
118
+
119
+ ## [2.5.2] - 2026-04-25
120
+
121
+ Hotfix release. Restores end-to-end functionality of synthesis, causal
122
+ triple extraction, fact extraction, LLM NER, and neighbor evolution
123
+ under any reasoning-style LLM (qwen3.5+, qwen3.6, nemotron-3, etc.).
124
+
125
+ ### Fixed
126
+
127
+ - **Reasoning-model token starvation across every LLM call site**.
128
+ Reasoning models emit hidden `<think>...</think>` tokens that count
129
+ against `num_predict` but never appear in the final `response` field
130
+ Ollama returns. Pre-2.5.2 token caps (`max_tokens=300`/`400`/`800`/
131
+ `1024`) were exhausted entirely by the thinking phase on these
132
+ models, leaving the JSON answer empty. Symptoms: synthesis fell back
133
+ to `"No specific answer found for: …"` on every query; causal triple
134
+ extraction persisted **0 edges** despite rich CTI text; LLM NER
135
+ silently no-opped; neighbor evolution `parse_failed{schema=...,
136
+ raw=""}` warnings flooded the log.
137
+
138
+ Bumped every `generate(..., max_tokens=...)` call site to give
139
+ reasoning models room to think *and* emit a final answer. Affected
140
+ files:
141
+
142
+ | File | Old cap | New cap |
143
+ |---|---|---|
144
+ | `note_constructor.py` (causal triples) | 300 | **8000** |
145
+ | `synthesis_generator.py` | 800 | 2500 |
146
+ | `fact_extractor.py` | 400 | 2500 |
147
+ | `entity_indexer.py` (NER) | 300 | 2500 |
148
+ | `memory_evolver.py` (2 sites) | 1024 | 2500 |
149
+
150
+ Causal extraction needs the largest budget because the prompt asks
151
+ the model to enumerate *every* causal relation in a passage; this
152
+ triggers the longest reasoning chains anywhere in the system.
153
+ Empirical against `qwen3.5:9b`: at 4000 tokens the call was
154
+ *stochastically* sufficient (eval_count varied 2.8k–4k+, ~70%
155
+ success), so 8000 is the conservative cap that keeps the success
156
+ rate above 95% on the same model. Other call sites converge with
157
+ less reasoning overhead so 2500 suffices.
158
+
159
+ - **LLM client timeout bumped 60s → 180s**. `LLMConfig.timeout` and
160
+ `OllamaProvider` constructor default were both 60 seconds — well
161
+ below the 60–120s wall-clock time of a 4000–8000 token reasoning
162
+ generation on a 9B-Q4_K_M model. `ReadTimeout` was firing during
163
+ causal extraction even when the model would have returned valid
164
+ JSON given another 30 seconds. Bumped both defaults plus
165
+ `config.default.yaml` to 180s.
166
+
167
+ Verified end-to-end on `qwen3.5:9b`:
168
+ - Synthesis: query "What CVE does DROPBEAR exploit?" returns
169
+ `"CVE-2024-3094"` with 1 source citation (was returning
170
+ `"No specific answer found for: …"` on every call pre-2.5.2).
171
+ - Causal extraction: corpus seeded with APT28/DROPBEAR/CVE-2024-3094
172
+ text yields a 4-triple JSON array in 137s wall time:
173
+ `APT28 → targets → manufacturing sector`,
174
+ `APT28 → uses → DROPBEAR`,
175
+ `DROPBEAR → exploits → CVE-2024-3094`,
176
+ `APT28 → attributed_to → Russian GRU Unit 26165`.
177
+
178
+ ### Operational note
179
+
180
+ Slow models. With 8000 tokens of reasoning budget, single causal
181
+ extraction calls now take 60–140s on a 9B model. `remember(sync=True)`
182
+ in this configuration will block 1–3 minutes per note. The default
183
+ async path (background enrichment queue) is the preferred mode.
184
+ Operators on faster hardware or smaller models can lower the caps via
185
+ config/env if needed, but the v2.5.2 defaults trade latency for
186
+ end-to-end correctness on the reference model.
187
+
188
+ ### Notes
189
+
190
+ This explains the `evolution_parse_failed` and `causal_triples
191
+ parse_failed` cascades documented in the v2.4.x Vigil incident. The
192
+ v2.4.2 PR #95 Tier 1/2 LLM observability surfaced the empty responses
193
+ but the root-cause attribution to token-cap-vs-thinking-budget waited
194
+ until the v2.5.1 perf-bench run made the failure reproducible end-to-end.
195
+
9
196
  ## [2.5.1] - 2026-04-25
10
197
 
11
198
  Hotfix release. Surfaced during the v2.5.0 perf benchmark run.
@@ -37,6 +37,49 @@ If your contribution needs TypeDB or OpenCTI, open an issue to discuss.
37
37
  We keep the extension boundary clear so contributors know their work
38
38
  will always remain open source.
39
39
 
40
+ ### For major features: Start with an RFC
41
+
42
+ If you're proposing a significant new feature (new subsystem, new backend,
43
+ breaking API change), open an RFC before writing code. RFCs live in
44
+ `docs/rfcs/` and follow the template from the existing RFCs in that
45
+ directory. Open a Discussion first to socialize the idea, then file a
46
+ draft RFC as a PR. This prevents wasted effort on work that won't be
47
+ accepted.
48
+
49
+ See [ROADMAP.md](ROADMAP.md) for the current priorities and what's
50
+ planned for upcoming releases.
51
+
52
+ ### Good first issues
53
+
54
+ Issues tagged [good first issue](https://github.com/rolandpg/zettelforge/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
55
+ have structured acceptance criteria in the issue body. Check the issue
56
+ for: which files to edit, test expectations, and example input/output.
57
+ If an issue is unclear, ask in the issue comments.
58
+
59
+ ## Issue triage
60
+
61
+ This project is maintained by a solo developer (per GOV-006). Here is
62
+ what you can expect:
63
+
64
+ - **New issues**: triaged within 7 days. You will get a response (even
65
+ if it's "not planned, closing").
66
+ - **Bug reports**: severity assessed within 7 days. P0 (crash, data
67
+ loss, security) gets a same-day response.
68
+ - **Feature requests**: tagged with `enhancement` on creation. The
69
+ maintainer will add `planned`, `deferred`, or `won't fix` within 7
70
+ days.
71
+ - **PR reviews**: first review within 14 days of submission. Smaller
72
+ PRs get reviewed faster.
73
+ - **Stale issues**: issues with no activity for 60 days are tagged
74
+ `stale` and closed after 14 more days without response. This keeps
75
+ the tracker manageable for a solo maintainer.
76
+
77
+ ## Contributor recognition
78
+
79
+ Every contributor is listed in [CONTRIBUTORS.md](CONTRIBUTORS.md),
80
+ regardless of contribution size. If you submit a PR that gets merged,
81
+ you will be added. If your name is missing, open a PR.
82
+
40
83
  ## Code Style
41
84
 
42
85
  - Follow PEP 8
@@ -0,0 +1,17 @@
1
+ # Contributors
2
+
3
+ Thank you to everyone who has contributed to ZettelForge.
4
+
5
+ ## Maintainers
6
+
7
+ - **Patrick G. Roland II** — creator and lead maintainer
8
+
9
+ ## Contributors
10
+
11
+ This file tracks individuals who have contributed code, documentation, design, or other improvements. The maintainer updates it with each release.
12
+
13
+ If you have contributed and your name is missing, please open a PR or issue.
14
+
15
+ ---
16
+
17
+ *This project uses a "thank you, next" acknowledgment model. All contributors are listed regardless of contribution size. A typo fix counts.*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zettelforge
3
- Version: 2.5.1
3
+ Version: 2.6.2
4
4
  Summary: ZettelForge: Agentic Memory System with vector search, knowledge graph, and synthesis
5
5
  Project-URL: Homepage, https://github.com/rolandpg/zettelforge
6
6
  Project-URL: Documentation, https://docs.threatrecall.ai
@@ -36,12 +36,16 @@ Requires-Dist: requests>=2.31.0
36
36
  Requires-Dist: structlog>=24.0.0
37
37
  Requires-Dist: tantivy>=0.11.0
38
38
  Provides-Extra: dev
39
+ Requires-Dist: fastapi>=0.100.0; extra == 'dev'
40
+ Requires-Dist: jinja2>=3.0.0; extra == 'dev'
39
41
  Requires-Dist: langchain-core>=0.2.0; extra == 'dev'
40
42
  Requires-Dist: mypy>=1.0.0; extra == 'dev'
43
+ Requires-Dist: psutil>=5.9.0; extra == 'dev'
41
44
  Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
42
45
  Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
43
46
  Requires-Dist: pytest>=7.0.0; extra == 'dev'
44
47
  Requires-Dist: ruff>=0.4.0; extra == 'dev'
48
+ Requires-Dist: uvicorn>=0.20.0; extra == 'dev'
45
49
  Provides-Extra: extensions
46
50
  Requires-Dist: zettelforge-enterprise>=2.1.0; extra == 'extensions'
47
51
  Provides-Extra: langchain
@@ -61,6 +65,8 @@ Requires-Dist: presidio-anonymizer>=2.2.0; extra == 'pii'
61
65
  Requires-Dist: spacy>=3.5.0; extra == 'pii'
62
66
  Provides-Extra: web
63
67
  Requires-Dist: fastapi>=0.100.0; extra == 'web'
68
+ Requires-Dist: jinja2>=3.0.0; extra == 'web'
69
+ Requires-Dist: psutil>=5.9.0; extra == 'web'
64
70
  Requires-Dist: uvicorn>=0.20.0; extra == 'web'
65
71
  Description-Content-Type: text/markdown
66
72
 
@@ -79,8 +85,9 @@ It extracts CVEs, threat actors, IOCs, and ATT&CK techniques from analyst notes
79
85
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
80
86
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)
81
87
  [![CI](https://github.com/rolandpg/zettelforge/actions/workflows/ci.yml/badge.svg)](https://github.com/rolandpg/zettelforge/actions)
88
+ [![Open Issues](https://img.shields.io/github/issues/rolandpg/zettelforge?color=blue)](https://github.com/rolandpg/zettelforge/issues)
82
89
 
83
- **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted beta](https://threatrecall.ai)**
90
+ **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted beta](https://threatrecall.ai) · [🗺️ Roadmap](ROADMAP.md)**
84
91
 
85
92
  <p align="center">
86
93
  <a href="https://www.buymeacoffee.com/xypher22pr0" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-green.png" alt="Buy Me a Coffee" style="height: 60px !important;width: 217px !important;" ></a>
@@ -13,8 +13,9 @@ It extracts CVEs, threat actors, IOCs, and ATT&CK techniques from analyst notes
13
13
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
14
14
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)
15
15
  [![CI](https://github.com/rolandpg/zettelforge/actions/workflows/ci.yml/badge.svg)](https://github.com/rolandpg/zettelforge/actions)
16
+ [![Open Issues](https://img.shields.io/github/issues/rolandpg/zettelforge?color=blue)](https://github.com/rolandpg/zettelforge/issues)
16
17
 
17
- **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted beta](https://threatrecall.ai)**
18
+ **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted beta](https://threatrecall.ai) · [🗺️ Roadmap](ROADMAP.md)**
18
19
 
19
20
  <p align="center">
20
21
  <a href="https://www.buymeacoffee.com/xypher22pr0" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-green.png" alt="Buy Me a Coffee" style="height: 60px !important;width: 217px !important;" ></a>
@@ -0,0 +1,94 @@
1
+ # ZettelForge Roadmap
2
+
3
+ Last updated: 2026-04-25
4
+
5
+ This document communicates what the maintainer is building, what is on hold, and what is out of scope. It is updated when priorities shift.
6
+
7
+ ---
8
+
9
+ ## Current release: v2.6.1
10
+
11
+ Shipped: 2026-04-25. See `CHANGELOG.md` for details.
12
+
13
+ The v2.6 series (RFC-013 through RFC-015) delivered PII detection (Presidio), configurable content size limits, and the Web Management Interface. The v2.5 series (RFC-009 through RFC-012) delivered the enrichment pipeline v2, local LLM backends, and unified provider config.
14
+
15
+ ---
16
+
17
+ ## v2.7.0 targets (next release)
18
+
19
+ Target: 2026-05-09. Scope is frozen at the items below. Everything else defers to v2.8.0 unless marked **P0**.
20
+
21
+ ### Must ship (P0)
22
+
23
+ - [ ] **Issue #125: Harden reasoning-model LLM budget plumbing.** Regression tests for `max_tokens` at each call site, config-overridable budgets, `thinking` tag stripping in `json_parse.py`, and a `reasoning_model: bool` auto-scaling flag. Post-#124 follow-up. (Est: 2-3 days)
24
+ - [ ] **Issue #73: Tighten CCCS metadata regexes (SEC-6 / SEC-7).** Low hanging security hardening. (Est: 0.5 day)
25
+ - [ ] **Issue #72: MemoryManager.remember(sync=True) dominates bulk ingest.** The YARA p95 plyara tail needs a timeout or chunked processing path. (Est: 1 day)
26
+
27
+ ### Nice to have (P1)
28
+
29
+ - [ ] **Issue #71: Add typed DetectionMeta extension to MemoryNote.Metadata.** Paves the way for richer entity metadata downstream. (Est: 0.5 day)
30
+ - [ ] **Issue #51: Ratchet governance coverage threshold from 67% toward 80%.** Incremental. (Est: 1 day)
31
+
32
+ ### Community items (open for contribution)
33
+
34
+ See the [good first issue](https://github.com/rolandpg/zettelforge/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label. These are pre-scoped with acceptance criteria:
35
+
36
+ - #47 — IPv6 address extraction
37
+ - #46 — YARA rule reference extraction
38
+ - #45 — Sigma rule ID extraction
39
+ - #39 — Threat actor alias mappings for Chinese APT groups
40
+ - #36 — Architecture decision records (ADRs)
41
+ - #44 — Example: MISP JSON feed ingestion
42
+ - #43 — Example: Slack bot for CTI queries
43
+ - #41 — Example: Jupyter notebook CTI analysis workflow
44
+
45
+ ---
46
+
47
+ ## Next release (v2.7.1+)
48
+
49
+ Target: approximately 2026-05-23. Provisional scope; will be finalized after v2.7.0 ships.
50
+
51
+ - [ ] **CrewAI tool wrapper** (#40). Integration path for CrewAI agents to use ZettelForge as a memory backend.
52
+ - [ ] **OpenCTI sync overhaul**. Improving the bidirectional sync reliability from the initial implementation.
53
+ - [ ] **Detection rules as first-class entities** (#feat/detection-rules-first-class branch). Sigma/YARA rules stored and searchable as knowledge graph nodes.
54
+
55
+ ---
56
+
57
+ ## Backlog / on hold
58
+
59
+ These are tracked but not actively scheduled:
60
+
61
+ - **MCP registry publish** (feat/mcp-registry-publish branch). Publishing the MCP server to the official MCP registry.
62
+ - **Enterprise split**. Separating the current monolithic package into community + enterprise tiers. Governance, license boundary, and packaging work. Not blocked, but deferred until community adoption justifies the overhead.
63
+ - **TypeDB read-path hardening**. Depth routing and schema versioning for the TypeDB backend. Most users run on JSONL/SQLite; TypeDB is a small fraction of the install base.
64
+ - **Conversational entity extractor** (stash: feature/RFC-001-conversational-entity-extractor). Interactive refinement of extracted entities by analyst chat. Requires UX thinking and a frontend update.
65
+ - **Pydantic v3 upgrade prep** (stash: test-fix/pydantic-v3-prep). Preparing internal models for Pydantic v3 migration. Low urgency; no upstream pressure yet.
66
+
67
+ ---
68
+
69
+ ## Out of scope (not building)
70
+
71
+ These have been proposed or discussed and explicitly decided against:
72
+
73
+ - **UI framework migration** (React, Vue, Svelte, etc.). The web GUI is a vanilla JS SPA using the ZettelForge Design System. No npm build step, no JS framework. This is intentional: the SPA must remain maintainable by a solo developer and installable with `pip install zettelforge[web]` without a separate build step. Not changing.
74
+ - **Docker containerization**. Deferred to v2.x post-v1.0 per the tech stack decision. The in-process architecture already makes deployment trivial.
75
+ - **Cloud-hosted memory backend**. ZettelForge is designed for local-first, air-gapped, and on-prem deployments. A cloud sync layer would compromise the security model and is not on the roadmap.
76
+ - **LangChain / LangGraph integration as a default**. Out of scope per the CLAUDE.md rules in this repo. Community wraps are welcome (see the CrewAI issue for how integration should work).
77
+
78
+ ---
79
+
80
+ ## Release cadence
81
+
82
+ - **Minor releases (v2.x.0)**: roughly every 2-3 weeks, bundling feature work and hardening.
83
+ - **Patch releases (v2.x.y)**: as needed for P0 bugs, security fixes, and regressions. No pre-scheduled date.
84
+ - **Major releases (v3.0.0+)**: not yet planned. The API is still evolving. A major version bump will come with a public deprecation notice and migration guide.
85
+
86
+ ## Commitment
87
+
88
+ This roadmap is a best-effort forecast, not a contract. Priorities shift based on user feedback, security findings, and the maintainer's availability (solo maintainer, GOV-006 declared).
89
+
90
+ Issues tagged with a target release are actively planned. Issues without a release tag are candidates for the next roadmap refresh.
91
+
92
+ ---
93
+
94
+ [Back to README](README.md)
@@ -214,7 +214,7 @@ llm:
214
214
  url: http://localhost:11434
215
215
  api_key: ""
216
216
  temperature: 0.1
217
- timeout: 60.0
217
+ timeout: 180.0 # v2.5.2: bumped from 60s for reasoning-model headroom
218
218
  max_retries: 2
219
219
  fallback: ""
220
220
  local_backend: llama-cpp-python # used when provider=local (RFC-011)
@@ -374,6 +374,8 @@ synthesis:
374
374
  # Env overrides:
375
375
  # ZETTELFORGE_PII_ENABLED=true
376
376
  # ZETTELFORGE_PII_ACTION=redact
377
+ # ZETTELFORGE_LIMITS_MAX_CONTENT_LENGTH=104857600
378
+ # ZETTELFORGE_LIMITS_RECALL_TIMEOUT=60
377
379
  #
378
380
  governance:
379
381
  enabled: true
@@ -385,9 +387,32 @@ governance:
385
387
  entities: []
386
388
  language: en
387
389
  nlp_model: en_core_web_sm
390
+ limits:
391
+ max_content_length: 52428800 # 50 MB, 0 = unlimited
392
+ recall_timeout_seconds: 30.0 # seconds, 0 = unlimited
388
393
 
389
394
 
390
- # ── Cache ───────────────────────────────────────────────────────────────────
395
+ # ── LanceDB Maintenance (RFC-009 Phase 1.5) ─────────────────────────────────
396
+ # Background daemon that prunes stale LanceDB version-history per shard.
397
+ #
398
+ # Examples:
399
+ # # Default — clean up every hour, keep versions < 1 hour old
400
+ # cleanup_interval_minutes: 60
401
+ # cleanup_older_than_seconds: 3600
402
+ #
403
+ # # Aggressive cleanup (high-ingestion environments)
404
+ # cleanup_interval_minutes: 15
405
+ # cleanup_older_than_seconds: 600
406
+ #
407
+ # # Disable cleanup entirely
408
+ # cleanup_interval_minutes: 0
409
+ #
410
+ lance:
411
+ cleanup_interval_minutes: 60
412
+ cleanup_older_than_seconds: 3600
413
+
414
+
415
+ # ── Cache
391
416
  # In-memory cache for TypeDB query results. Reduces round-trips for
392
417
  # frequently accessed entities and relationships.
393
418
  #
@@ -434,3 +459,32 @@ logging:
434
459
  level: INFO
435
460
  log_intents: true
436
461
  log_causal: true
462
+
463
+
464
+ # ── Web UI (RFC-015) ─────────────────────────────────────────────────────────
465
+ # ZettelForge Web Management Interface — SPA served at GET /.
466
+ #
467
+ # Examples:
468
+ # # Default — enabled on 0.0.0.0:8088
469
+ # enabled: true
470
+ # host: 0.0.0.0
471
+ # port: 8088
472
+ #
473
+ # # Custom port (e.g., behind nginx reverse proxy)
474
+ # enabled: true
475
+ # host: 127.0.0.1
476
+ # port: 9000
477
+ #
478
+ # # Disable web UI entirely (library-only mode)
479
+ # enabled: false
480
+ #
481
+ # Env overrides:
482
+ # ZETTELFORGE_WEB_ENABLED=true
483
+ # ZETTELFORGE_WEB_PORT=8088
484
+ # ZETTELFORGE_WEB_UI_DIR=/path/to/ui
485
+ #
486
+ web:
487
+ enabled: true
488
+ host: 0.0.0.0
489
+ port: 8088
490
+
@@ -137,9 +137,9 @@ TB-1 ─────────────────────────
137
137
 
138
138
  | ID | Threat | Component | Risk | Mitigation |
139
139
  |----|--------|-----------|------|------------|
140
- | D-01 | Large content in `remember()` exhausts memory or blocks the enrichment queue | MemoryManager (P1) | **Medium** — degraded performance | `remember_report()` chunks long documents. No explicit size limit on `remember()` content. Enrichment queue has `maxsize=500` backpressure. |
140
+ | D-01 | Large content in `remember()` exhausts memory or blocks the enrichment queue | MemoryManager (P1) | **Low** — gracefully rejected | `governance.limits.max_content_length` (RFC-014, default 50 MB) blocks oversized content with a clear error. `remember_report()` chunks long documents. Enrichment queue has `maxsize=500` backpressure. |
141
141
  | D-02 | LLM provider (ollama, litellm) hangs and blocks `remember()` | LLM Provider (TB-4) | **High** — operation blocks | OllamaProvider has timeout (RFC-010, default 60s). LitellmProvider has timeout + num_retries. `generate()` returns empty string on recoverable failure. Fallback provider (e.g., local -> ollama) gives alternative path. |
142
- | D-03 | Malicious query triggers deep graph traversal exhausting time/resources | BlendedRetriever | **Medium** — slow recall | `max_graph_depth` config (default 2) limits BFS hops. `default_k` (default 10) limits results. No timeout on recall queries. |
142
+ | D-03 | Malicious query triggers deep graph traversal exhausting time/resources | BlendedRetriever | **Medium** — bounded, but timeout may still block | `governance.limits.recall_timeout_seconds` (RFC-014, default 30s) applies a wall-clock timeout to the recall pipeline, but the current `ThreadPoolExecutor`-based approach must not be treated as guaranteeing prompt return on timeout. `max_graph_depth` (default 2) limits BFS hops. `default_k` (default 10) limits results. Reclassify to **Low** only after the timeout path is verified to return promptly and log `recall_timed_out` without waiting for the running task to finish. |
143
143
  | D-04 | spaCy model download blocks first `remember()` when PII is enabled | PIIValidator (lazy load) | **Low** — delayed first call (~2-3 seconds) | One-time download cost. Matching fastembed pattern. Can be pre-downloaded for air-gapped deployments. |
144
144
 
145
145
  ### 2.6 Elevation of Privilege
@@ -158,8 +158,8 @@ TB-1 ─────────────────────────
158
158
  |------------|-------|--------------|
159
159
  | **Critical** | 2 | T-01 (storage tampering), I-01 (unencrypted data at rest), E-02 (governance bypass via filesystem) |
160
160
  | **High** | 7 | S-01 (spoofed MCP client), S-03 (config tampering), T-02 (config security downgrade), R-01 (repudiation without audit), I-02 (PII in stored notes), D-02 (LLM provider hang), E-01 (cross-tenant data access) |
161
- | **Medium** | 9 | S-02 (fake LLM provider), T-04 (retrieval poisoning), R-02, R-03, I-04 (error message leakage), D-01, D-03, E-03 |
162
- | **Low** | 1 | D-04 (PII model download delay) |
161
+ | **Medium** | 7 | S-02 (fake LLM provider), T-04 (retrieval poisoning), R-02, R-03, I-04 (error message leakage), E-03 |
162
+ | **Low** | 3 | D-01, D-03, D-04 (PII model download delay) |
163
163
 
164
164
  ### Top 5 Mitigations (Priority Order)
165
165
 
@@ -181,6 +181,8 @@ TB-1 ─────────────────────────
181
181
  | API key redaction | I-03 | `LLMConfig.__repr__` redacts api_key and sensitive extra keys | Unit tests in `test_llm_providers.py` |
182
182
  | PII detection + redaction | I-02 | PIIValidator (RFC-013): log/redact/block | Unit tests in `test_pii_validator.py` |
183
183
  | LLM provider timeout | D-02 | `OllamaProvider` timeout=60s, `LiteLLMProvider` timeout + num_retries | Unit tests (RFC-010, RFC-012) |
184
+ | Content size limit | D-01 | `governance.limits.max_content_length` (RFC-014, default 50 MB) blocks oversized content | Unit tests in `test_governance.py` |
185
+ | Recall timeout | D-03 | `governance.limits.recall_timeout_seconds` (RFC-014, default 30s) wraps recall in ThreadPoolExecutor with wall-clock timeout | Unit tests in `test_governance.py` |
184
186
  | Config env-var resolution | I-03 | `${ENV_VAR}` syntax prevents raw secrets in YAML | Unit tests |
185
187
  | Configurable model provider | S-02, E-03 | `provider` key selects backend; no implicit unauthenticated outbound calls | Config validation |
186
188
  | Enrichment queue backpressure | D-01 | `maxsize=500` bounded queue | Code review |
@@ -189,7 +191,6 @@ TB-1 ─────────────────────────
189
191
 
190
192
  | Recommendation | Threat(s) | Effort | Priority |
191
193
  |---------------|-----------|--------|----------|
192
- | Add content size limit to `remember()` | D-01 | Small | P3 |
193
194
  | Add global exception handler that sanitizes error output | I-04 | Medium | P2 |
194
195
  | Add TLS verification option for self-hosted LLM endpoints | S-02 | Small | P2 |
195
196
  | Add config file integrity check (SHA-256 of default vs. loaded) | T-02, S-03 | Medium | P3 |
@@ -231,6 +232,7 @@ Per GOV-021, the following data types exist in the system:
231
232
 
232
233
  | Change | RFC/PR | Date | Threat Model Impact |
233
234
  |--------|--------|------|---------------------|
235
+ | Content size limits + recall timeout | RFC-014 | 2026-04-25 | Mitigation for D-01 (content size limit, default 50 MB); partial mitigation for D-03 (timeout) |
234
236
  | PII detection and redaction | RFC-013 (PR #118) | 2026-04-25 | New control for I-02; new attack surface (D-04); PII text logging fixed |
235
237
  | LiteLLM unified provider | RFC-012 (PR #108) | 2026-04-25 | New provider for I-03 (API keys); new outbound traffic pattern (TB-4) |
236
238
  | Local LLM backend selection | RFC-011 (PR #104) | 2026-04-25 | No new threat surface — extends existing local provider |