zettelforge 2.6.2__tar.gz → 2.7.0__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 (398) hide show
  1. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/workflows/ci.yml +1 -1
  2. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/workflows/stale.yml +1 -1
  3. {zettelforge-2.6.2 → zettelforge-2.7.0}/CHANGELOG.md +53 -0
  4. {zettelforge-2.6.2 → zettelforge-2.7.0}/PKG-INFO +106 -79
  5. zettelforge-2.7.0/README.md +288 -0
  6. zettelforge-2.7.0/SCOPING_DOC.md +283 -0
  7. {zettelforge-2.6.2 → zettelforge-2.7.0}/config.default.yaml +15 -1
  8. zettelforge-2.7.0/docs/how-to/build-extensions.md +199 -0
  9. zettelforge-2.7.0/docs/how-to/configure-sigma-ingestion.md +183 -0
  10. zettelforge-2.7.0/docs/how-to/configure-yara-ingestion.md +223 -0
  11. zettelforge-2.7.0/docs/how-to/integrate-with-crewai.md +203 -0
  12. zettelforge-2.7.0/docs/how-to/integrate-with-langchain.md +210 -0
  13. zettelforge-2.7.0/docs/how-to/maintain-lancedb.md +82 -0
  14. zettelforge-2.7.0/docs/how-to/set-up-mcp-server.md +197 -0
  15. zettelforge-2.7.0/docs/how-to/use-detection-rules.md +191 -0
  16. zettelforge-2.7.0/docs/marketing/awesome-list-submissions.md +210 -0
  17. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/configuration.md +34 -2
  18. zettelforge-2.7.0/docs/reference/detection-rules-schema.md +416 -0
  19. zettelforge-2.7.0/docs/reference/editions.md +257 -0
  20. zettelforge-2.7.0/docs/reference/entity-indexer-concurrency.md +346 -0
  21. zettelforge-2.7.0/docs/reference/kg-edge-schema.md +415 -0
  22. zettelforge-2.7.0/docs/reference/mcp-protocol.md +723 -0
  23. zettelforge-2.7.0/docs/reference/sigma-schema-reference.md +367 -0
  24. zettelforge-2.7.0/docs/reference/yara-schema-reference.md +396 -0
  25. zettelforge-2.7.0/docs/rfcs/RFC-002a-retrieval-plumbing.md +214 -0
  26. zettelforge-2.7.0/docs/rfcs/RFC-016-osint-layer.md +411 -0
  27. zettelforge-2.7.0/docs/rfcs/RFC-017-memsad-write-time-defenses.md +402 -0
  28. zettelforge-2.7.0/examples/crewai_cti_crew.py +162 -0
  29. zettelforge-2.7.0/examples/cti_analysis.ipynb +381 -0
  30. zettelforge-2.7.0/examples/ingest_misp.py +467 -0
  31. zettelforge-2.7.0/examples/quickstart.py +35 -0
  32. zettelforge-2.7.0/examples/sample_misp_event.json +121 -0
  33. {zettelforge-2.6.2 → zettelforge-2.7.0}/mkdocs.yml +25 -9
  34. {zettelforge-2.6.2 → zettelforge-2.7.0}/pyproject.toml +23 -1
  35. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/__init__.py +5 -1
  36. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/config.py +47 -0
  37. zettelforge-2.7.0/src/zettelforge/integrations/__init__.py +22 -0
  38. zettelforge-2.7.0/src/zettelforge/integrations/crewai.py +368 -0
  39. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_providers/litellm_provider.py +36 -7
  40. zettelforge-2.7.0/src/zettelforge/memory_defense.py +384 -0
  41. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/memory_manager.py +66 -9
  42. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/ontology.py +5 -0
  43. zettelforge-2.7.0/src/zettelforge/osint/__init__.py +80 -0
  44. zettelforge-2.7.0/src/zettelforge/osint/collectors/__init__.py +5 -0
  45. zettelforge-2.7.0/src/zettelforge/osint/collectors/breach/__init__.py +17 -0
  46. zettelforge-2.7.0/src/zettelforge/osint/collectors/breach/breach_directory.py +46 -0
  47. zettelforge-2.7.0/src/zettelforge/osint/collectors/breach/hibp_collector.py +46 -0
  48. zettelforge-2.7.0/src/zettelforge/osint/collectors/infrastructure/__init__.py +25 -0
  49. zettelforge-2.7.0/src/zettelforge/osint/collectors/infrastructure/bgp_collector.py +125 -0
  50. zettelforge-2.7.0/src/zettelforge/osint/collectors/infrastructure/cert_collector.py +124 -0
  51. zettelforge-2.7.0/src/zettelforge/osint/collectors/infrastructure/dns_collector.py +211 -0
  52. zettelforge-2.7.0/src/zettelforge/osint/collectors/infrastructure/port_scanner.py +109 -0
  53. zettelforge-2.7.0/src/zettelforge/osint/collectors/infrastructure/whois_collector.py +286 -0
  54. zettelforge-2.7.0/src/zettelforge/osint/collectors/people/__init__.py +20 -0
  55. zettelforge-2.7.0/src/zettelforge/osint/collectors/people/holehe_collector.py +47 -0
  56. zettelforge-2.7.0/src/zettelforge/osint/collectors/people/hunter_collector.py +54 -0
  57. zettelforge-2.7.0/src/zettelforge/osint/collectors/people/namechk_collector.py +42 -0
  58. zettelforge-2.7.0/src/zettelforge/osint/collectors/social/__init__.py +17 -0
  59. zettelforge-2.7.0/src/zettelforge/osint/collectors/social/hashtag_tracker.py +46 -0
  60. zettelforge-2.7.0/src/zettelforge/osint/collectors/social/twitter_collector.py +49 -0
  61. zettelforge-2.7.0/src/zettelforge/osint/collectors/tech/__init__.py +17 -0
  62. zettelforge-2.7.0/src/zettelforge/osint/collectors/tech/builtwith_collector.py +53 -0
  63. zettelforge-2.7.0/src/zettelforge/osint/collectors/tech/wappalyzer_collector.py +56 -0
  64. zettelforge-2.7.0/src/zettelforge/osint/entity_resolver.py +164 -0
  65. zettelforge-2.7.0/src/zettelforge/osint/investigation.py +129 -0
  66. zettelforge-2.7.0/src/zettelforge/osint/ontology.py +472 -0
  67. zettelforge-2.7.0/src/zettelforge/osint/transform_registry.py +123 -0
  68. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/scripts/human_eval_sampler.py +2 -2
  69. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/scripts/telemetry_dashboard.py +1 -1
  70. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/telemetry.py +50 -14
  71. zettelforge-2.7.0/tests/test_crewai_integration.py +312 -0
  72. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_llm_client.py +6 -2
  73. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_llm_providers.py +123 -9
  74. zettelforge-2.7.0/tests/test_memory_defense.py +90 -0
  75. zettelforge-2.7.0/tests/test_osint_collectors.py +438 -0
  76. zettelforge-2.7.0/tests/test_osint_entities.py +281 -0
  77. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_performance.py +7 -3
  78. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/search.js +16 -1
  79. zettelforge-2.6.2/README.md +0 -270
  80. zettelforge-2.6.2/examples/quickstart.py +0 -18
  81. zettelforge-2.6.2/src/zettelforge/integrations/__init__.py +0 -10
  82. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/CODEOWNERS +0 -0
  83. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  84. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  85. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/SECURITY.md +0 -0
  86. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/dependabot.yml +0 -0
  87. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/pull_request_template.md +0 -0
  88. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/workflows/docs.yml +0 -0
  89. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/workflows/publish.yml +0 -0
  90. {zettelforge-2.6.2 → zettelforge-2.7.0}/.github/workflows/snyk-security.yml +0 -0
  91. {zettelforge-2.6.2 → zettelforge-2.7.0}/.gitignore +0 -0
  92. {zettelforge-2.6.2 → zettelforge-2.7.0}/ARCHITECTURE.md +0 -0
  93. {zettelforge-2.6.2 → zettelforge-2.7.0}/CODEOWNERS +0 -0
  94. {zettelforge-2.6.2 → zettelforge-2.7.0}/CODE_OF_CONDUCT.md +0 -0
  95. {zettelforge-2.6.2 → zettelforge-2.7.0}/CONTRIBUTING.md +0 -0
  96. {zettelforge-2.6.2 → zettelforge-2.7.0}/CONTRIBUTORS.md +0 -0
  97. {zettelforge-2.6.2 → zettelforge-2.7.0}/Dockerfile +0 -0
  98. {zettelforge-2.6.2 → zettelforge-2.7.0}/GOVERNANCE.md +0 -0
  99. {zettelforge-2.6.2 → zettelforge-2.7.0}/LICENSE +0 -0
  100. {zettelforge-2.6.2 → zettelforge-2.7.0}/MANIFEST.in +0 -0
  101. {zettelforge-2.6.2 → zettelforge-2.7.0}/ROADMAP.md +0 -0
  102. {zettelforge-2.6.2 → zettelforge-2.7.0}/SECURITY.md +0 -0
  103. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/BENCHMARK_REPORT.md +0 -0
  104. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
  105. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/auto_ralph.py +0 -0
  106. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/benchmark_harness.py +0 -0
  107. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/cti_benchmark_v2.py +0 -0
  108. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/cti_retrieval_benchmark.py +0 -0
  109. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/cti_retrieval_results.json +0 -0
  110. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/cti_v2_results.json +0 -0
  111. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/ctibench_benchmark.py +0 -0
  112. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/ctibench_results.json +0 -0
  113. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/dataset.json +0 -0
  114. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/enterprise-attack.json +0 -0
  115. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/evolve_benchmark.py +0 -0
  116. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/evolve_results.json +0 -0
  117. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/graph_test.py +0 -0
  118. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/locomo_benchmark.py +0 -0
  119. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/locomo_results.json +0 -0
  120. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
  121. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/memoryagentbench.py +0 -0
  122. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/memoryagentbench_results.json +0 -0
  123. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/mempalace_benchmark.py +0 -0
  124. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/mempalace_results.json +0 -0
  125. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/naive_memory.py +0 -0
  126. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/opencti_benchmark.py +0 -0
  127. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/ragas_benchmark.py +0 -0
  128. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/ragas_cti_results.json +0 -0
  129. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/ragas_results.json +0 -0
  130. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/results/benchmark_report.md +0 -0
  131. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/results/ralph_optimization_log.json +0 -0
  132. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/scale_benchmark.py +0 -0
  133. {zettelforge-2.6.2 → zettelforge-2.7.0}/benchmarks/scale_results.json +0 -0
  134. {zettelforge-2.6.2 → zettelforge-2.7.0}/config.example.yaml +0 -0
  135. {zettelforge-2.6.2 → zettelforge-2.7.0}/docker/docker-compose.yml +0 -0
  136. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/.well-known/security.txt +0 -0
  137. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/CNAME +0 -0
  138. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/THREAT_MODEL.md +0 -0
  139. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/architecture-diagram.mmd +0 -0
  140. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/archive/PACKAGE_SUMMARY.md +0 -0
  141. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/archive/README.md +0 -0
  142. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/archive/SKILL.md +0 -0
  143. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/ZettelForge_Architecture.mmd +0 -0
  144. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/architecture-overview.mmd +0 -0
  145. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/architecture-read-path.mmd +0 -0
  146. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/architecture-write-path.mmd +0 -0
  147. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/cf-analytics.js +0 -0
  148. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/demo.gif +0 -0
  149. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/favicon-16.png +0 -0
  150. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/favicon-32.png +0 -0
  151. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/favicon-512.png +0 -0
  152. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/favicon-64.png +0 -0
  153. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/favicon-apple-touch.png +0 -0
  154. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/favicon-old.svg +0 -0
  155. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/favicon.svg +0 -0
  156. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/logo.svg +0 -0
  157. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/social-preview.png +0 -0
  158. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/threatrecall-lockup-monogram.svg +0 -0
  159. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/threatrecall-lockup.svg +0 -0
  160. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/threatrecall-logo-flat.svg +0 -0
  161. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/threatrecall-logo-philosophy.md +0 -0
  162. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/threatrecall-logo.png +0 -0
  163. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/threatrecall-mark.png +0 -0
  164. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/zettelforge_architecture-light.svg +0 -0
  165. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/assets/zettelforge_architecture.svg +0 -0
  166. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/brand/brandIdentity.md +0 -0
  167. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/brand/colors_and_type.css +0 -0
  168. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/explanation/architecture.md +0 -0
  169. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/explanation/epistemic-tiers.md +0 -0
  170. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/explanation/llm-budgets-and-timeouts.md +0 -0
  171. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/explanation/stix-in-zettelforge.md +0 -0
  172. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/explanation/two-phase-pipeline.md +0 -0
  173. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/explanation/zettelkasten-philosophy.md +0 -0
  174. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/configure-lancedb.md +0 -0
  175. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/configure-opencti.md +0 -0
  176. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/configure-pii.md +0 -0
  177. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/configure-typedb.md +0 -0
  178. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/ingest-news-report.md +0 -0
  179. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/integrate-llm-agent.md +0 -0
  180. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/migrate-jsonl-to-sqlite.md +0 -0
  181. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/query-apt-tools.md +0 -0
  182. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/reproduce-benchmarks.md +0 -0
  183. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/resolve-aliases.md +0 -0
  184. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/run-temporal-query.md +0 -0
  185. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/store-threat-actor.md +0 -0
  186. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/troubleshoot.md +0 -0
  187. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/upgrade.md +0 -0
  188. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/how-to/use-web-interface.md +0 -0
  189. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/human-evaluation-rubric.md +0 -0
  190. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/index.md +0 -0
  191. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/llms.txt +0 -0
  192. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/narrative/2026-04-16-the-memory-problem.md +0 -0
  193. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/overrides/main.html +0 -0
  194. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/architecture-deep-dive.md +0 -0
  195. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/governance-controls.md +0 -0
  196. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/memory-manager-api.md +0 -0
  197. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/module-inventory.md +0 -0
  198. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/retrieval-policies.md +0 -0
  199. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/stix-schema.md +0 -0
  200. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/reference/web-api.md +0 -0
  201. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -0
  202. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-002-universal-llm-provider.md +0 -0
  203. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-003-adversarial-review.md +0 -0
  204. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-003-read-path-depth-routing.md +0 -0
  205. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-007-operational-telemetry.md +0 -0
  206. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-009-enrichment-pipeline-v2.md +0 -0
  207. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-010-enrichment-hotfix.md +0 -0
  208. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-011-local-llm-backend-config.md +0 -0
  209. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-012-litellm-unified-provider.md +0 -0
  210. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-013-presidio-pii-detection.md +0 -0
  211. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-014-content-limits.md +0 -0
  212. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/rfcs/RFC-015-zettelforge-web-gui.md +0 -0
  213. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/stylesheets/brand-tokens.css +0 -0
  214. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/stylesheets/extra.css +0 -0
  215. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/stylesheets/fonts/Neuropol.otf +0 -0
  216. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/tutorials/01-quickstart.md +0 -0
  217. {zettelforge-2.6.2 → zettelforge-2.7.0}/docs/tutorials/02-first-cti-report.md +0 -0
  218. {zettelforge-2.6.2 → zettelforge-2.7.0}/examples/athf_bridge.py +0 -0
  219. {zettelforge-2.6.2 → zettelforge-2.7.0}/examples/mcp_claude_code.md +0 -0
  220. {zettelforge-2.6.2 → zettelforge-2.7.0}/governance/controls.yaml +0 -0
  221. {zettelforge-2.6.2 → zettelforge-2.7.0}/pr-body.md +0 -0
  222. {zettelforge-2.6.2 → zettelforge-2.7.0}/scripts/migrate_jsonl_to_sqlite.py +0 -0
  223. {zettelforge-2.6.2 → zettelforge-2.7.0}/scripts/rebuild_index.py +0 -0
  224. {zettelforge-2.6.2 → zettelforge-2.7.0}/scripts/record-demo.sh +0 -0
  225. {zettelforge-2.6.2 → zettelforge-2.7.0}/scripts/typedb-setup.sh +0 -0
  226. {zettelforge-2.6.2 → zettelforge-2.7.0}/scripts/zettelforge-rebuild.service +0 -0
  227. {zettelforge-2.6.2 → zettelforge-2.7.0}/scripts/zettelforge-rebuild.timer +0 -0
  228. {zettelforge-2.6.2 → zettelforge-2.7.0}/server.json +0 -0
  229. {zettelforge-2.6.2 → zettelforge-2.7.0}/skills/claude-code-skill.md +0 -0
  230. {zettelforge-2.6.2 → zettelforge-2.7.0}/skills/openclaw-skill.md +0 -0
  231. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/__main__.py +0 -0
  232. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/alias_resolver.py +0 -0
  233. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/backend_factory.py +0 -0
  234. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/blended_retriever.py +0 -0
  235. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/cache.py +0 -0
  236. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/consolidation.py +0 -0
  237. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/demo.py +0 -0
  238. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/detection/__init__.py +0 -0
  239. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/detection/base.py +0 -0
  240. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/detection/consumers.py +0 -0
  241. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/detection/explainer.py +0 -0
  242. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/edition.py +0 -0
  243. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/entity_indexer.py +0 -0
  244. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/extensions.py +0 -0
  245. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/fact_extractor.py +0 -0
  246. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/governance_validator.py +0 -0
  247. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/graph_retriever.py +0 -0
  248. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/integrations/langchain_retriever.py +0 -0
  249. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/intent_classifier.py +0 -0
  250. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/json_parse.py +0 -0
  251. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/knowledge_graph.py +0 -0
  252. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/lance_maintenance.py +0 -0
  253. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_client.py +0 -0
  254. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_providers/__init__.py +0 -0
  255. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_providers/base.py +0 -0
  256. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_providers/local_provider.py +0 -0
  257. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_providers/mock_provider.py +0 -0
  258. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_providers/ollama_provider.py +0 -0
  259. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/llm_providers/registry.py +0 -0
  260. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/log.py +0 -0
  261. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/mcp/__init__.py +0 -0
  262. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/mcp/__main__.py +0 -0
  263. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/mcp/server.py +0 -0
  264. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/memory_evolver.py +0 -0
  265. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/memory_store.py +0 -0
  266. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/memory_updater.py +0 -0
  267. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/note_constructor.py +0 -0
  268. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/note_schema.py +0 -0
  269. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/observability.py +0 -0
  270. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/ocsf.py +0 -0
  271. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/pii_validator.py +0 -0
  272. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/retry.py +0 -0
  273. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/scripts/compact_lance.py +0 -0
  274. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/scripts/telemetry_aggregator.py +0 -0
  275. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/__init__.py +0 -0
  276. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/cli.py +0 -0
  277. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/entities.py +0 -0
  278. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/ingest.py +0 -0
  279. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/parser.py +0 -0
  280. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/schemas/NOTICE.md +0 -0
  281. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/schemas/__init__.py +0 -0
  282. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +0 -0
  283. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +0 -0
  284. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/schemas/sigma-filters-schema.json +0 -0
  285. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sigma/tags.py +0 -0
  286. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/sqlite_backend.py +0 -0
  287. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/storage_backend.py +0 -0
  288. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/synthesis_generator.py +0 -0
  289. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/synthesis_validator.py +0 -0
  290. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/vector_memory.py +0 -0
  291. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/vector_retriever.py +0 -0
  292. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/__init__.py +0 -0
  293. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/cccs_metadata.py +0 -0
  294. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/cli.py +0 -0
  295. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/entities.py +0 -0
  296. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/ingest.py +0 -0
  297. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/parser.py +0 -0
  298. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/schemas/CCCS_YARA.yml +0 -0
  299. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +0 -0
  300. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/schemas/NOTICE.md +0 -0
  301. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/schemas/__init__.py +0 -0
  302. {zettelforge-2.6.2 → zettelforge-2.7.0}/src/zettelforge/yara/tags.py +0 -0
  303. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/__init__.py +0 -0
  304. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/benchmark_scale.py +0 -0
  305. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/conftest.py +0 -0
  306. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/fixtures/sigma/cloud_example.yml +0 -0
  307. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/fixtures/sigma/correlation_example.yml +0 -0
  308. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/fixtures/sigma/process_creation_example.yml +0 -0
  309. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/fixtures/sigma/tagged_example.yml +0 -0
  310. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/fixtures/yara/malware_hash.yar +0 -0
  311. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/fixtures/yara/technique_loader.yar +0 -0
  312. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/fixtures/yara/webshell.yar +0 -0
  313. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_basic.py +0 -0
  314. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_blended_retriever.py +0 -0
  315. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_causal_extraction.py +0 -0
  316. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_config.py +0 -0
  317. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_consolidation.py +0 -0
  318. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_conversational_entities.py +0 -0
  319. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_core.py +0 -0
  320. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_cti_integration.py +0 -0
  321. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_detection_explainer.py +0 -0
  322. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_detection_rule_entities.py +0 -0
  323. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_edition.py +0 -0
  324. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_embedding.py +0 -0
  325. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_entity_indexer_races.py +0 -0
  326. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_extensions.py +0 -0
  327. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_fact_extractor.py +0 -0
  328. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_governance.py +0 -0
  329. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_governance_spec_drift.py +0 -0
  330. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_graph_retriever.py +0 -0
  331. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_human_eval_sampler.py +0 -0
  332. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_intent_classifier.py +0 -0
  333. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_json_parse.py +0 -0
  334. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_kg_edge_schema.py +0 -0
  335. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_lance_maintenance.py +0 -0
  336. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_langchain_retriever.py +0 -0
  337. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_logging_compliance.py +0 -0
  338. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_mcp_server.py +0 -0
  339. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_memory_evolver.py +0 -0
  340. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_memory_updater.py +0 -0
  341. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_pii_validator.py +0 -0
  342. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_recall_integration.py +0 -0
  343. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_sigma_entities.py +0 -0
  344. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_sigma_ingest.py +0 -0
  345. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_sigma_parser.py +0 -0
  346. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_sqlite_backend.py +0 -0
  347. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_sqlite_integration.py +0 -0
  348. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_storage_backend.py +0 -0
  349. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_telemetry_aggregator.py +0 -0
  350. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_telemetry_collector.py +0 -0
  351. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_telemetry_dashboard.py +0 -0
  352. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_telemetry_integration.py +0 -0
  353. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_temporal_graph.py +0 -0
  354. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_two_phase_e2e.py +0 -0
  355. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_typedb_client.py +0 -0
  356. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_web_api.py +0 -0
  357. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_yara_entities.py +0 -0
  358. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_yara_ingest.py +0 -0
  359. {zettelforge-2.6.2 → zettelforge-2.7.0}/tests/test_yara_parser.py +0 -0
  360. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/app.py +0 -0
  361. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/auth.py +0 -0
  362. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/mcp_server.py +0 -0
  363. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/static/css/design_tokens.css +0 -0
  364. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/base.html +0 -0
  365. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/components/remember_panel.html +0 -0
  366. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/components/result_card.html +0 -0
  367. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/components/search_bar.html +0 -0
  368. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/components/synthesis_block.html +0 -0
  369. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/components/tab_bar.html +0 -0
  370. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/config_editor.html +0 -0
  371. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/templates/index.html +0 -0
  372. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/assets/favicon-16.png +0 -0
  373. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/assets/favicon-32.png +0 -0
  374. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/assets/favicon-512.png +0 -0
  375. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/assets/favicon-apple-touch.png +0 -0
  376. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/assets/logo.svg +0 -0
  377. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/assets/threatrecall-lockup.svg +0 -0
  378. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/assets/zettelforge_architecture.svg +0 -0
  379. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/colors_and_type.css +0 -0
  380. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/favicon.svg +0 -0
  381. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/fonts/Neuropol.otf +0 -0
  382. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/index.html +0 -0
  383. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/app.js +0 -0
  384. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/components/header.js +0 -0
  385. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/components/result-card.js +0 -0
  386. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/components/sidebar.js +0 -0
  387. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/components/spinner.js +0 -0
  388. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/components/tabs.js +0 -0
  389. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/components/toast.js +0 -0
  390. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/lib/api.js +0 -0
  391. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/lib/state.js +0 -0
  392. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/configuration.js +0 -0
  393. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/dashboard.js +0 -0
  394. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/entities.js +0 -0
  395. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/history.js +0 -0
  396. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/ingest.js +0 -0
  397. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/knowledge-graph.js +0 -0
  398. {zettelforge-2.6.2 → zettelforge-2.7.0}/web/ui/js/views/logs.js +0 -0
@@ -102,7 +102,7 @@ jobs:
102
102
 
103
103
  - name: Upload coverage
104
104
  if: matrix.python-version == '3.12'
105
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2
105
+ uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354
106
106
  with:
107
107
  file: ./coverage.xml
108
108
  fail_ci_if_error: false
@@ -12,7 +12,7 @@ jobs:
12
12
  stale:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/stale@v9
15
+ - uses: actions/stale@v10
16
16
  with:
17
17
  repo-token: ${{ secrets.GITHUB_TOKEN }}
18
18
 
@@ -6,6 +6,59 @@ Versioning follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.7.0] - 2026-05-26
10
+
11
+ Security and OSINT release. Adds the RFC-016 OSINT layer and the first
12
+ SEC-011 / MemSAD-inspired write-time memory-poisoning defense. No data
13
+ migration is required. The new memory defense ships in audit mode by default.
14
+
15
+ ### Added
16
+
17
+ - **OSINT layer scaffold and Phase 1 collectors** (RFC-016). Adds
18
+ `zettelforge.osint` with infrastructure, breach, people, social, and
19
+ technology collector packages; OSINT ontology and relation extensions;
20
+ entity canonicalization helpers; collector registry; and tests covering
21
+ DNS, WHOIS, certificates, BGP, ports, breach, people, social, and tech
22
+ collector contracts. Optional runtime dependencies are available with
23
+ `pip install zettelforge[osint]`.
24
+ - **Write-time memory anomaly defense** (SEC-011 / MemSAD). New
25
+ `MemoryAnomalyGate` scores candidate notes before persistence using
26
+ MemSAD-style max/mean embedding similarity against recent domain
27
+ calibration notes plus character n-gram Jensen-Shannon divergence to
28
+ reduce synonym/paraphrase evasion. Config lives under
29
+ `governance.memory_defense`; default mode is `audit`, with `block` and
30
+ `quarantine` available once a deployment has a clean calibration corpus.
31
+ - **Quarantine path for rejected memory writes.** In `quarantine` mode,
32
+ flagged notes are written to JSONL forensic quarantine and are not exposed
33
+ to recall, entity lookup, LanceDB, or graph traversal.
34
+ - **CrewAI integration** (issue #40). New optional extra
35
+ `pip install zettelforge[crewai]` exposes `ZettelForgeRecallTool`,
36
+ `ZettelForgeRememberTool`, and `ZettelForgeSynthesizeTool` as CrewAI
37
+ `BaseTool` subclasses. CTI-focused crews can now use ZettelForge as a
38
+ drop-in alternative to CrewAI's existing Mem0 memory tools, with
39
+ per-tool description copy aimed at routing the LLM to the right tool
40
+ (recall for lookups, remember for findings, synthesize for final answers).
41
+ See `examples/crewai_cti_crew.py` for a runnable two-agent demo.
42
+ Tests gated on `pytest.importorskip("crewai")`; 11 pass against
43
+ crewai 1.14.x.
44
+
45
+ ### Changed
46
+
47
+ - **Telemetry attribution compatibility.** `caller` is now supported in
48
+ telemetry events while the previous `actor` field and method arguments
49
+ remain backward-compatible for existing dashboards and tests.
50
+ - **Real LLM integration and performance tests are explicit opt-in.**
51
+ Set `ZETTELFORGE_RUN_LLM_INTEGRATION=1` or
52
+ `ZETTELFORGE_RUN_PERFORMANCE_TESTS=1` to run environment-sensitive suites.
53
+ The default regression suite is now deterministic on machines without
54
+ local LLM credentials or dedicated benchmark hardware.
55
+
56
+ ### Tests
57
+
58
+ - Added focused memory-defense tests for insufficient calibration, audit-mode
59
+ anomaly detection, and quarantine writes.
60
+ - Default regression gate: `742 passed, 13 skipped`.
61
+
9
62
  ## [2.6.2] - 2026-04-27
10
63
 
11
64
  UI/UX release. Fixes the `/config` page so the Apply button actually works
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zettelforge
3
- Version: 2.6.2
3
+ Version: 2.7.0
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
@@ -35,8 +35,12 @@ Requires-Dist: pyyaml>=6.0
35
35
  Requires-Dist: requests>=2.31.0
36
36
  Requires-Dist: structlog>=24.0.0
37
37
  Requires-Dist: tantivy>=0.11.0
38
+ Provides-Extra: crewai
39
+ Requires-Dist: crewai>=1.14.0; extra == 'crewai'
38
40
  Provides-Extra: dev
41
+ Requires-Dist: dnspython>=2.4.0; extra == 'dev'
39
42
  Requires-Dist: fastapi>=0.100.0; extra == 'dev'
43
+ Requires-Dist: ipwhois>=1.2.0; extra == 'dev'
40
44
  Requires-Dist: jinja2>=3.0.0; extra == 'dev'
41
45
  Requires-Dist: langchain-core>=0.2.0; extra == 'dev'
42
46
  Requires-Dist: mypy>=1.0.0; extra == 'dev'
@@ -44,6 +48,7 @@ Requires-Dist: psutil>=5.9.0; extra == 'dev'
44
48
  Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
45
49
  Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
46
50
  Requires-Dist: pytest>=7.0.0; extra == 'dev'
51
+ Requires-Dist: python-whois>=0.9.0; extra == 'dev'
47
52
  Requires-Dist: ruff>=0.4.0; extra == 'dev'
48
53
  Requires-Dist: uvicorn>=0.20.0; extra == 'dev'
49
54
  Provides-Extra: extensions
@@ -59,6 +64,10 @@ Requires-Dist: llama-cpp-python>=0.3.0; extra == 'local-all'
59
64
  Requires-Dist: onnxruntime-genai>=0.4.0; extra == 'local-all'
60
65
  Provides-Extra: local-onnx
61
66
  Requires-Dist: onnxruntime-genai>=0.4.0; extra == 'local-onnx'
67
+ Provides-Extra: osint
68
+ Requires-Dist: dnspython>=2.4.0; extra == 'osint'
69
+ Requires-Dist: ipwhois>=1.2.0; extra == 'osint'
70
+ Requires-Dist: python-whois>=0.9.0; extra == 'osint'
62
71
  Provides-Extra: pii
63
72
  Requires-Dist: presidio-analyzer>=2.2.0; extra == 'pii'
64
73
  Requires-Dist: presidio-anonymizer>=2.2.0; extra == 'pii'
@@ -82,18 +91,18 @@ It extracts CVEs, threat actors, IOCs, and ATT&CK techniques from analyst notes
82
91
 
83
92
  [![PyPI](https://img.shields.io/pypi/v/zettelforge)](https://pypi.org/project/zettelforge/)
84
93
  [![Downloads/month](https://static.pepy.tech/personalized-badge/zettelforge?period=month&units=international_system&left_color=grey&right_color=blue&left_text=downloads%2Fmonth)](https://pepy.tech/projects/zettelforge)
94
+ [![Star History](https://api.star-history.com/svg?repos=rolandpg/zettelforge&type=Date)](https://star-history.com/#rolandpg/zettelforge&Date)
85
95
  [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
86
96
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)
87
97
  [![CI](https://github.com/rolandpg/zettelforge/actions/workflows/ci.yml/badge.svg)](https://github.com/rolandpg/zettelforge/actions)
88
98
  [![Open Issues](https://img.shields.io/github/issues/rolandpg/zettelforge?color=blue)](https://github.com/rolandpg/zettelforge/issues)
89
99
 
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)**
100
+ **[Star](https://github.com/rolandpg/zettelforge) · [`pip install zettelforge`](https://pypi.org/project/zettelforge/) · [Docs](https://docs.threatrecall.ai/) · [ThreatRecall (hosted)](https://threatrecall.ai) · [Changelog](CHANGELOG.md)**
101
+
102
+ > **v2.6.2** (2026-04-27): Config web editor ships with working dropdowns for all enum fields (LLM/embedding provider, log level, PII action, synthesis format) and a working Apply button. New `[crewai]` extra exposes ZettelForge as CrewAI tools -- `pip install zettelforge[crewai]`. [Full changelog](CHANGELOG.md)
91
103
 
92
104
  <p align="center">
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>
94
- </p>
95
- <p align="center">
96
- <img src="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/demo.gif" width="720" alt="ZettelForge demo — CTI agentic memory in action">
105
+ <img src="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/demo.gif" width="720" alt="ZettelForge demo -- CTI agentic memory in action">
97
106
  </p>
98
107
 
99
108
  > If ZettelForge fits a CTI workflow you run, a star is the fastest signal that this category is worth continuing to invest in.
@@ -104,9 +113,9 @@ Every SOC loses analysts. When they leave, investigation context, actor attribut
104
113
 
105
114
  General-purpose AI memory systems don't fix this for security teams. They can't tell APT28 from Fancy Bear, don't know that CVE-2024-3094 is the XZ Utils backdoor, can't parse Sigma or YARA, and have no concept of MITRE ATT&CK technique IDs. When a CTI analyst gives them a year of intel reports, they get back fuzzy semantic search over chat history.
106
115
 
107
- ZettelForge was built for analysts who think in threat graphs. It extracts CVEs, threat actors, IOCs, and ATT&CK techniques automatically, resolves aliases across naming conventions, builds a knowledge graph with causal relationships, and retrieves memories using intent-aware blended search all in-process, with no external API dependency.
116
+ ZettelForge was built for analysts who think in threat graphs. It extracts CVEs, threat actors, IOCs, and ATT&CK techniques automatically, resolves aliases across naming conventions, builds a knowledge graph with causal relationships, and retrieves memories using intent-aware blended search -- all in-process, with no external API dependency.
108
117
 
109
- >"Memory augmentation closes 33% of the gap between small and large models on CTI tasks (CTI-REALM, Microsoft 2026)." [1]
118
+ > Memory augmentation closes 33% of the gap between small and large models on CTI tasks ([CTI-REALM, Microsoft 2026](https://www.microsoft.com/en-us/security/blog/2026/03/20/cti-realm-a-new-benchmark-for-end-to-end-detection-rule-generation-with-ai-agents/), using GPT-4 as the large-model baseline). See [full benchmark report](benchmarks/BENCHMARK_REPORT.md) for methodology and comparisons.
110
119
 
111
120
  | Capability | ZettelForge | Mem0 | Graphiti | Cognee |
112
121
  |---|---|---|---|---|
@@ -124,31 +133,33 @@ ZettelForge was built for analysts who think in threat graphs. It extracts CVEs,
124
133
  <picture>
125
134
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture.svg">
126
135
  <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture-light.svg">
127
- <img src="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture.svg" width="720" alt="ZettelForge architecture neural recall loop: ingest, enrich, retrieve, synthesize, backed by SQLite + LanceDB">
136
+ <img src="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture.svg" width="720" alt="ZettelForge architecture -- neural recall loop: ingest, enrich, retrieve, synthesize, backed by SQLite + LanceDB">
128
137
  </picture>
129
138
  </p>
130
139
 
131
140
 
132
141
  ## Features
133
142
 
134
- **Entity Extraction** Automatically identifies CVEs, threat actors, IOCs (IPs, domains, hashes, URLs, emails), MITRE ATT&CK techniques, campaigns, intrusion sets, tools, people, locations, and organizations. Regex + LLM NER with STIX 2.1 types throughout.
143
+ **Entity Extraction** -- Automatically identifies CVEs, threat actors, IOCs (IPs, domains, hashes, URLs, emails), MITRE ATT&CK techniques, campaigns, intrusion sets, tools, people, locations, and organizations. Regex + LLM NER with STIX 2.1 types throughout.
135
144
 
136
- **Knowledge Graph** Entities become nodes, co-occurrence becomes edges. LLM infers causal triples ("APT28 *uses* Cobalt Strike"). Temporal edges and supersession track how intelligence evolves.
145
+ **Knowledge Graph** -- Entities become nodes, co-occurrence becomes edges. LLM infers causal triples ("APT28 *uses* Cobalt Strike"). Temporal edges and supersession track how intelligence evolves.
137
146
 
138
- **Alias Resolution** APT28, Fancy Bear, Sofacy, STRONTIUM all resolve to the same actor node. Works automatically on store and recall.
147
+ **Alias Resolution** -- APT28, Fancy Bear, Sofacy, STRONTIUM all resolve to the same actor node. Works automatically on store and recall.
139
148
 
140
- **Blended Retrieval** Vector similarity (768-dim fastembed, ONNX) + graph traversal (BFS over knowledge graph edges), weighted by intent classification. Five intent types: factual, temporal, relational, exploratory, causal.
149
+ **Blended Retrieval** -- Vector similarity (768-dim fastembed, ONNX) + graph traversal (BFS over knowledge graph edges), weighted by intent classification. Five intent types: factual, temporal, relational, exploratory, causal.
141
150
 
142
- **Memory Evolution** With `evolve=True`, new intel is compared to existing memory. LLM decides ADD, UPDATE, DELETE, or NOOP. Stale intel gets superseded. Contradictions get resolved. Duplicates get skipped.
151
+ **Memory Evolution** -- With `evolve=True`, new intel is compared to existing memory. LLM decides ADD, UPDATE, DELETE, or NOOP. Stale intel gets superseded. Contradictions get resolved. Duplicates get skipped.
143
152
 
144
- **RAG Synthesis** Synthesize answers across all stored memories with `direct_answer` format.
153
+ **RAG Synthesis** -- Synthesize answers across all stored memories with `direct_answer` format.
145
154
 
146
- **In-process by architecture** fastembed (ONNX) for embeddings, llama-cpp-python for optional local LLM inference, SQLite + LanceDB for storage, and Ollama on localhost by default. No external API keys are required. Outbound network access may occur on first run when embedding/LLM models are downloaded; after models are preloaded, it can run fully offline (including on air-gapped hosts).
155
+ **In-process by architecture** -- fastembed (ONNX) for embeddings, llama-cpp-python for optional local LLM inference, SQLite + LanceDB for storage, and Ollama on localhost by default. No external API keys are required. Outbound network access may occur on first run when embedding/LLM models are downloaded; after models are preloaded, it can run fully offline (including on air-gapped hosts).
147
156
 
148
- **Audit logging in OCSF schema** Every operation emits a structured event in the Open Cybersecurity Schema Framework format. What you do with the log stream (SIEM, WORM store, nothing) is up to you.
157
+ **Audit logging in OCSF schema** -- Every operation emits a structured event in the Open Cybersecurity Schema Framework format. What you do with the log stream (SIEM, WORM store, nothing) is up to you.
149
158
 
150
159
  ## Quick Start
151
160
 
161
+ ### 30-second hello world (no LLM required)
162
+
152
163
  ```bash
153
164
  pip install zettelforge
154
165
  ```
@@ -158,30 +169,37 @@ from zettelforge import MemoryManager
158
169
 
159
170
  mm = MemoryManager()
160
171
 
161
- # Store threat intel entities extracted automatically
172
+ # Store CTI -- entities (CVEs, actors, ATT&CK IDs, IOCs) extracted via regex
162
173
  mm.remember("APT28 uses Cobalt Strike for lateral movement via T1021")
174
+ mm.remember("APT28 (Fancy Bear) targets NATO defense contractors with spear-phishing")
175
+ mm.remember("CVE-2024-3094 is the XZ Utils backdoor (CVSS 10.0) affecting sshd")
163
176
 
164
- # Recall with alias resolution
165
- results = mm.recall("What tools does Fancy Bear use?")
166
- # Returns the APT28 note (APT28 = Fancy Bear, resolved automatically)
167
-
168
- # Synthesize across all memories
169
- answer = mm.synthesize("Summarize known APT28 TTPs")
177
+ # Recall blends vector + graph search; alias resolution kicks in (Fancy Bear -> APT28)
178
+ for note in mm.recall("What tools does Fancy Bear use?", k=3):
179
+ print(f"[{note.metadata.tier}] {note.content.raw}")
170
180
  ```
171
181
 
172
- No TypeDB, no Ollama, no Docker — just `pip install`. Embeddings run in-process via fastembed. LLM features (extraction, synthesis) activate when Ollama is available.
182
+ That works on a fresh `pip install` with no external services. Embeddings run in-process via fastembed (~80MB ONNX model downloaded on first call). `MemoryManager()` writes to `~/.amem/` by default; override with `ZETTELFORGE_DATA_DIR` or via config. A runnable copy lives at [`examples/quickstart.py`](examples/quickstart.py).
173
183
 
174
- ### With Ollama (enables LLM features)
184
+ ### Add an LLM for synthesis and richer extraction
175
185
 
176
186
  ```bash
177
- ollama pull qwen2.5:3b && ollama serve
178
- # ZettelForge auto-detects Ollama for extraction and synthesis
187
+ ollama pull qwen3.5:9b && ollama serve
179
188
  ```
180
189
 
190
+ ```python
191
+ # With Ollama running, synthesize() returns a real summary across stored notes
192
+ answer = mm.synthesize("Summarize known APT28 TTPs")
193
+ print(answer["synthesis"]["answer"])
194
+ # Background LLM NER also enriches stored notes with additional entities
195
+ ```
196
+
197
+ ZettelForge auto-detects Ollama. To use a different provider (`local` llama-cpp, `litellm` for 100+ providers, `mock` for tests), see [Configuration](#configuration). Without an LLM, `synthesize()` still returns a structured response but the `answer` field is a fallback placeholder -- only `remember` and `recall` produce useful results in pip-only mode.
198
+
181
199
  ### Memory Evolution
182
200
 
183
201
  ```python
184
- # New intel arrives evolve=True enables memory evolution:
202
+ # New intel arrives -- evolve=True enables memory evolution:
185
203
  # LLM extracts facts, compares to existing notes, decides ADD/UPDATE/DELETE/NOOP
186
204
  mm.remember(
187
205
  "APT28 has shifted tactics. They dropped DROPBEAR and now exploit edge devices.",
@@ -194,55 +212,77 @@ mm.remember(
194
212
 
195
213
  Every `remember()` call triggers a pipeline:
196
214
 
197
- 1. **Entity Extraction** regex + LLM NER identifies CVEs, intrusion sets, threat actors, tools, campaigns, ATT&CK techniques, IOCs (IPv4, domain, URL, MD5/SHA1/SHA256, email), people, locations, organizations, events, activities, and temporal references (19 types)
198
- 2. **Knowledge Graph Update** entities become nodes, co-occurrence becomes edges, LLM infers causal triples
199
- 3. **Vector Embedding** 768-dim fastembed (ONNX, in-process, 7ms/embed) stored in LanceDB
200
- 4. **Supersession Check** entity overlap detection marks stale notes as superseded
201
- 5. **Dual-Stream Write** fast path returns in ~45ms; causal enrichment is deferred to a background worker
215
+ 1. **Entity Extraction** -- regex + LLM NER identifies CVEs, intrusion sets, threat actors, tools, campaigns, ATT&CK techniques, IOCs (IPv4, domain, URL, MD5/SHA1/SHA256, email), people, locations, organizations, events, activities, and temporal references (19 types)
216
+ 2. **Knowledge Graph Update** -- entities become nodes, co-occurrence becomes edges, LLM infers causal triples
217
+ 3. **Vector Embedding** -- 768-dim fastembed (ONNX, in-process, 7ms/embed) stored in LanceDB
218
+ 4. **Supersession Check** -- entity overlap detection marks stale notes as superseded
219
+ 5. **Dual-Stream Write** -- fast path returns in ~45ms; causal enrichment is deferred to a background worker
202
220
 
203
221
  Every `recall()` call blends two retrieval strategies:
204
222
 
205
- 1. **Vector similarity** semantic search over embeddings
206
- 2. **Graph traversal** BFS over knowledge graph edges, scored by hop distance
207
- 3. **Intent routing** query classified as factual/temporal/relational/causal/exploratory, weights adjusted per type
208
- 4. **Cross-encoder reranking** ms-marco-MiniLM reorders final results by relevance
223
+ 1. **Vector similarity** -- semantic search over embeddings
224
+ 2. **Graph traversal** -- BFS over knowledge graph edges, scored by hop distance
225
+ 3. **Intent routing** -- query classified as factual/temporal/relational/causal/exploratory, weights adjusted per type
226
+ 4. **Cross-encoder reranking** -- ms-marco-MiniLM reorders final results by relevance
209
227
 
210
- ## Benchmarks
228
+ ## Use ZettelForge in Claude Desktop in 60 seconds
211
229
 
212
- Evaluated against published academic benchmarks:
213
-
214
- | Benchmark | What it measures | Score |
215
- |---|---|---|
216
- | **CTI Retrieval** | Attribution, CVE linkage, multi-hop | **75.0%** |
217
- | **RAGAS** | Retrieval quality (keyword presence) | **78.1%** |
218
- | **LOCOMO** (ACL 2024) | Conversational memory recall | **22.0%** *(with Ollama cloud models)* |
230
+ ```bash
231
+ pip install zettelforge
232
+ ```
219
233
 
220
- See the [full benchmark report](benchmarks/BENCHMARK_REPORT.md) for methodology and analysis.
234
+ Create or edit `.claude.json` in your project root (or `~/.claude/.claude.json` for global access):
221
235
 
222
- ## MCP Server (Claude Code)
236
+ ```json
237
+ {
238
+ "mcpServers": {
239
+ "zettelforge": {
240
+ "command": "python3",
241
+ "args": ["-m", "zettelforge.mcp"]
242
+ }
243
+ }
244
+ }
245
+ ```
223
246
 
224
- Add ZettelForge as a memory backend for Claude Code:
247
+ If ZettelForge is installed in a virtual environment, use the full path to that Python interpreter:
225
248
 
226
249
  ```json
227
250
  {
228
251
  "mcpServers": {
229
252
  "zettelforge": {
230
- "command": "python3",
253
+ "command": "/home/user/.venvs/zettelforge/bin/python",
231
254
  "args": ["-m", "zettelforge.mcp"]
232
255
  }
233
256
  }
234
257
  }
235
258
  ```
236
259
 
237
- Your Claude Code agent can now remember and recall threat intelligence across sessions.
260
+ Start Claude Code and verify the tools are available:
261
+
262
+ ```bash
263
+ claude
264
+ # Inside the session, ask: "What tools do you have available from zettelforge?"
265
+ ```
266
+
267
+ Seven tools are exposed: `zettelforge_remember`, `zettelforge_recall`, `zettelforge_synthesize`, `zettelforge_entity`, `zettelforge_graph`, `zettelforge_stats`, and `zettelforge_sync` (requires enterprise package). See the [MCP protocol reference](docs/reference/mcp-protocol.md) for full schemas, JSON-RPC request/response examples, error codes, and the lazy-singleton lifecycle. For troubleshooting, virtualenv paths, and manual tool testing, see [set-up-mcp-server](docs/how-to/set-up-mcp-server.md).
268
+
269
+ ## Benchmarks
270
+
271
+ Evaluated against published academic benchmarks:
272
+
273
+ | Benchmark | What it measures | Score |
274
+ |---|---|---|
275
+ | **CTI Retrieval** (CTIBench subset) | Attribution, CVE linkage, multi-hop | **75.0%** |
276
+ | **RAGAS** | Retrieval quality (keyword presence) | **78.1%** |
277
+ | **LOCOMO** (ACL 2024) | Conversational memory recall | **22.0%** |
238
278
 
239
- Exposed tools: `remember`, `recall`, `synthesize`, `entity`, `graph`, `stats`.
279
+ The **Score** column reports ZettelForge measurements run with Ollama-hosted models, with one exception: the LOCOMO row was re-measured at v2.1.1 using an Ollama cloud judge for evaluation grading (not local generation). See the [full benchmark report](benchmarks/BENCHMARK_REPORT.md) for benchmark-specific methodology, version history, and per-suite judge configuration.
240
280
 
241
281
  ## Detection Rules as Memory (Sigma + YARA)
242
282
 
243
283
  Sigma and YARA rules are first-class memory primitives. Parse, validate, and ingest a rule and its tags become graph edges: MITRE ATT&CK techniques, CVEs, threat-actor aliases, tools, and malware families resolve against the same ontology as every other note. A shared `DetectionRule` supertype carries `SigmaRule` and `YaraRule` subtypes, so a single rule UUID is addressable across both formats.
244
284
 
245
- Sigma rules are validated against the vendored [SigmaHQ JSON schema](https://github.com/SigmaHQ/sigma-specification). YARA rules are parsed with plyara and checked against the [CCCS YARA metadata standard](https://github.com/CybercentreCanada/CCCS-Yara) (tiers: `strict`, `warn`, `non_cccs`). Ingest is idempotent re-ingesting an unchanged rule returns the original note via a content-hashed `source_ref`.
285
+ Sigma rules are validated against the vendored [SigmaHQ JSON schema](https://github.com/SigmaHQ/sigma-specification). YARA rules are parsed with plyara and checked against the [CCCS YARA metadata standard](https://github.com/CybercentreCanada/CCCS-Yara) (tiers: `strict`, `warn`, `non_cccs`). Ingest is idempotent -- re-ingesting an unchanged rule returns the original note via a content-hashed `source_ref`.
246
286
 
247
287
  ```python
248
288
  from zettelforge import MemoryManager
@@ -259,11 +299,11 @@ ingest_yara("rules/webshell_china_chopper.yar", mm, tier="warn")
259
299
  python -m zettelforge.sigma.ingest /path/to/sigma/rules/
260
300
  python -m zettelforge.yara.ingest /path/to/yara/rules/ --tier warn
261
301
 
262
- # CI fixture check parse + validate, no writes
302
+ # CI fixture check -- parse + validate, no writes
263
303
  python -m zettelforge.sigma.ingest rules/ --dry-run
264
304
  ```
265
305
 
266
- An LLM rule explainer (`zettelforge.detection.explainer.explain`) produces a structured JSON summary intent, key fields, evasion notes, false-positive hypotheses for any `DetectionRule`. It runs synchronously on demand in v1; async enrichment-queue wiring is v1.1. Rate-limited via `ZETTELFORGE_EXPLAIN_RPM` (default 60 calls/minute).
306
+ An LLM rule explainer (`zettelforge.detection.explainer.explain`) produces a structured JSON summary -- intent, key fields, evasion notes, false-positive hypotheses -- for any `DetectionRule`. It runs synchronously on demand in v1; async enrichment-queue wiring is v1.1. Rate-limited via `ZETTELFORGE_EXPLAIN_RPM` (default 60 calls/minute).
267
307
 
268
308
  References: [Sigma spec](https://github.com/SigmaHQ/sigma-specification), [SigmaHQ rules](https://github.com/SigmaHQ/sigma), [CCCS YARA](https://github.com/CybercentreCanada/CCCS-Yara), [YARA docs](https://yara.readthedocs.io).
269
309
 
@@ -282,26 +322,18 @@ python examples/athf_bridge.py /path/to/hunts/
282
322
  See [examples/athf_bridge.py](examples/athf_bridge.py).
283
323
 
284
324
 
285
- ## Extensions
325
+ ## ThreatRecall (Hosted)
286
326
 
287
- ZettelForge ships a complete agentic memory core. Everything documented above works from a single `pip install`.
327
+ [ThreatRecall](https://threatrecall.ai) is the commercial distribution of ZettelForge with enterprise extensions enabled. It is offered as managed SaaS by default, with optional self-hosted on-prem and air-gapped deployments for classified environments. Enterprise add-ons:
288
328
 
289
- For teams that want TypeDB-scale graph storage, OpenCTI integration, or multi-tenant deployment, optional extensions are available:
329
+ - **TypeDB STIX 2.1 backend** -- schema-enforced ontology with inference rules
330
+ - **OpenCTI sync** -- bi-directional sync with your OpenCTI instance
331
+ - **Multi-tenant auth** -- OAuth/JWT with per-tenant data isolation
332
+ - **Sigma rule generation** -- detection rules from extracted IOCs (upcoming)
290
333
 
291
- | Extension | What it adds |
292
- |---|---|
293
- | TypeDB STIX 2.1 backend | Schema-enforced ontology with inference rules |
294
- | OpenCTI sync | Bi-directional sync with OpenCTI instances |
295
- | Multi-tenant auth | OAuth/JWT with per-tenant isolation |
296
- | Sigma rule generation | Detection rules from extracted IOCs |
334
+ SaaS deploys in minutes with no infrastructure to maintain. Self-hosted ships as a deployable bundle for environments where outbound network egress is restricted or prohibited.
297
335
 
298
- Extensions install separately:
299
-
300
- ```bash
301
- pip install zettelforge-enterprise
302
- ```
303
-
304
- **Hosted (private beta):** [ThreatRecall](https://threatrecall.ai) is the managed SaaS version of ZettelForge with enterprise extensions enabled. Currently accepting waitlist signups and a limited number of design partners.
336
+ **[Join the waitlist](https://threatrecall.ai)** -- currently onboarding design partners.
305
337
 
306
338
  ## Configuration
307
339
 
@@ -319,17 +351,13 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup.
319
351
 
320
352
  ## License
321
353
 
322
- MIT See [LICENSE](LICENSE).
323
-
324
- ## About the author
354
+ MIT -- See [LICENSE](LICENSE).
325
355
 
326
- Built by **Patrick Roland** Director of SOC Services at Summit 7 Systems, where he built the Vigilance MxDR practice from the ground up. Navy nuclear veteran, CISSP, CCP (CMMC 2.0 Professional). [LinkedIn](https://www.linkedin.com/in/patrickgroland/).
356
+ Built by **Patrick Roland** -- [LinkedIn](https://www.linkedin.com/in/patrickgroland/) | Director of SOC Services, Summit 7 Systems | Navy nuclear veteran | CISSP, CCP (CMMC 2.0 Professional)
327
357
 
328
358
  ## Support the Project
329
359
 
330
- ZettelForge is MIT-licensed. If it's useful in your workflow and you'd like to help keep it maintained:
331
-
332
- <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: 40px !important;width: 145px !important;" ></a>
360
+ ZettelForge is MIT-licensed. Star the repo, open issues, and submit PRs all contributions are welcome.
333
361
 
334
362
  ## Acknowledgments
335
363
 
@@ -339,4 +367,3 @@ ZettelForge is MIT-licensed. If it's useful in your workflow and you'd like to h
339
367
  - Benchmarked against [LOCOMO](https://snap-research.github.io/locomo/) (ACL 2024) and [CTIBench](https://arxiv.org/abs/2406.07599) (NeurIPS 2024)
340
368
  - [LanceDB](https://lancedb.com) | [fastembed](https://github.com/qdrant/fastembed) | [Pydantic](https://pydantic.dev) | [TypeDB](https://typedb.com)
341
369
 
342
- [1]: https://www.microsoft.com/en-us/security/blog/2026/03/20/cti-realm-a-new-benchmark-for-end-to-end-detection-rule-generation-with-ai-agents/