zettelforge 2.3.0__tar.gz → 2.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. {zettelforge-2.3.0 → zettelforge-2.4.1}/CHANGELOG.md +140 -0
  2. {zettelforge-2.3.0 → zettelforge-2.4.1}/CODE_OF_CONDUCT.md +1 -1
  3. zettelforge-2.4.1/PKG-INFO +324 -0
  4. zettelforge-2.4.1/README.md +269 -0
  5. {zettelforge-2.3.0 → zettelforge-2.4.1}/SECURITY.md +24 -3
  6. {zettelforge-2.3.0 → zettelforge-2.4.1}/config.default.yaml +5 -2
  7. zettelforge-2.4.1/docs/.well-known/security.txt +10 -0
  8. zettelforge-2.4.1/docs/assets/cf-analytics.js +9 -0
  9. zettelforge-2.4.1/docs/assets/favicon-16.png +0 -0
  10. zettelforge-2.4.1/docs/assets/favicon-32.png +0 -0
  11. zettelforge-2.4.1/docs/assets/favicon-512.png +0 -0
  12. zettelforge-2.4.1/docs/assets/favicon-64.png +0 -0
  13. zettelforge-2.4.1/docs/assets/favicon-apple-touch.png +0 -0
  14. zettelforge-2.4.1/docs/assets/favicon.svg +33 -0
  15. zettelforge-2.4.1/docs/assets/logo.svg +46 -0
  16. zettelforge-2.4.1/docs/assets/social-preview.png +0 -0
  17. zettelforge-2.4.1/docs/assets/threatrecall-lockup-monogram.svg +41 -0
  18. zettelforge-2.4.1/docs/assets/threatrecall-lockup.svg +39 -0
  19. zettelforge-2.4.1/docs/assets/threatrecall-logo-flat.svg +29 -0
  20. zettelforge-2.4.1/docs/assets/zettelforge_architecture-light.svg +105 -0
  21. zettelforge-2.4.1/docs/assets/zettelforge_architecture.svg +105 -0
  22. zettelforge-2.4.1/docs/brand/brandIdentity.md +266 -0
  23. zettelforge-2.4.1/docs/brand/colors_and_type.css +286 -0
  24. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/configure-typedb.md +6 -4
  25. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/migrate-jsonl-to-sqlite.md +3 -1
  26. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/troubleshoot.md +24 -2
  27. zettelforge-2.4.1/docs/human-evaluation-rubric.md +136 -0
  28. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/index.md +10 -4
  29. zettelforge-2.4.1/docs/reference/architecture-deep-dive.md +380 -0
  30. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/reference/configuration.md +4 -4
  31. zettelforge-2.4.1/docs/reference/module-inventory.md +461 -0
  32. zettelforge-2.4.1/docs/rfcs/RFC-007-operational-telemetry.md +321 -0
  33. zettelforge-2.4.1/docs/stylesheets/brand-tokens.css +158 -0
  34. zettelforge-2.4.1/docs/stylesheets/extra.css +70 -0
  35. zettelforge-2.4.1/docs/stylesheets/fonts/Neuropol.otf +0 -0
  36. zettelforge-2.4.1/docs/superpowers/research/2026-04-17-test-suite-audit.md +178 -0
  37. {zettelforge-2.3.0 → zettelforge-2.4.1}/mkdocs.yml +15 -1
  38. {zettelforge-2.3.0 → zettelforge-2.4.1}/pyproject.toml +5 -1
  39. zettelforge-2.4.1/server.json +21 -0
  40. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/__init__.py +1 -1
  41. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/config.py +12 -2
  42. zettelforge-2.4.1/src/zettelforge/detection/__init__.py +24 -0
  43. zettelforge-2.4.1/src/zettelforge/detection/base.py +63 -0
  44. zettelforge-2.4.1/src/zettelforge/detection/consumers.py +77 -0
  45. zettelforge-2.4.1/src/zettelforge/detection/explainer.py +320 -0
  46. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/integrations/langchain_retriever.py +3 -6
  47. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/memory_manager.py +70 -1
  48. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/ontology.py +129 -4
  49. zettelforge-2.4.1/src/zettelforge/scripts/human_eval_sampler.py +175 -0
  50. zettelforge-2.4.1/src/zettelforge/scripts/telemetry_aggregator.py +176 -0
  51. zettelforge-2.4.1/src/zettelforge/scripts/telemetry_dashboard.py +256 -0
  52. zettelforge-2.4.1/src/zettelforge/sigma/__init__.py +31 -0
  53. zettelforge-2.4.1/src/zettelforge/sigma/cli.py +123 -0
  54. zettelforge-2.4.1/src/zettelforge/sigma/entities.py +249 -0
  55. zettelforge-2.4.1/src/zettelforge/sigma/ingest.py +234 -0
  56. zettelforge-2.4.1/src/zettelforge/sigma/parser.py +148 -0
  57. zettelforge-2.4.1/src/zettelforge/sigma/schemas/NOTICE.md +10 -0
  58. zettelforge-2.4.1/src/zettelforge/sigma/schemas/__init__.py +1 -0
  59. zettelforge-2.4.1/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +326 -0
  60. zettelforge-2.4.1/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +247 -0
  61. zettelforge-2.4.1/src/zettelforge/sigma/schemas/sigma-filters-schema.json +101 -0
  62. zettelforge-2.4.1/src/zettelforge/sigma/tags.py +86 -0
  63. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/sqlite_backend.py +252 -153
  64. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/storage_backend.py +9 -0
  65. zettelforge-2.4.1/src/zettelforge/telemetry.py +340 -0
  66. zettelforge-2.4.1/src/zettelforge/yara/__init__.py +27 -0
  67. zettelforge-2.4.1/src/zettelforge/yara/cccs_metadata.py +258 -0
  68. zettelforge-2.4.1/src/zettelforge/yara/cli.py +177 -0
  69. zettelforge-2.4.1/src/zettelforge/yara/entities.py +269 -0
  70. zettelforge-2.4.1/src/zettelforge/yara/ingest.py +327 -0
  71. zettelforge-2.4.1/src/zettelforge/yara/parser.py +110 -0
  72. zettelforge-2.4.1/src/zettelforge/yara/schemas/CCCS_YARA.yml +306 -0
  73. zettelforge-2.4.1/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +160 -0
  74. zettelforge-2.4.1/src/zettelforge/yara/schemas/NOTICE.md +11 -0
  75. zettelforge-2.4.1/src/zettelforge/yara/schemas/__init__.py +1 -0
  76. zettelforge-2.4.1/src/zettelforge/yara/tags.py +74 -0
  77. zettelforge-2.4.1/tests/fixtures/sigma/cloud_example.yml +20 -0
  78. zettelforge-2.4.1/tests/fixtures/sigma/correlation_example.yml +14 -0
  79. zettelforge-2.4.1/tests/fixtures/sigma/process_creation_example.yml +17 -0
  80. zettelforge-2.4.1/tests/fixtures/sigma/tagged_example.yml +30 -0
  81. zettelforge-2.4.1/tests/fixtures/yara/malware_hash.yar +19 -0
  82. zettelforge-2.4.1/tests/fixtures/yara/technique_loader.yar +23 -0
  83. zettelforge-2.4.1/tests/fixtures/yara/webshell.yar +19 -0
  84. zettelforge-2.4.1/tests/test_causal_extraction.py +102 -0
  85. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_config.py +53 -0
  86. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_conversational_entities.py +50 -11
  87. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_core.py +2 -2
  88. zettelforge-2.4.1/tests/test_detection_explainer.py +328 -0
  89. zettelforge-2.4.1/tests/test_detection_rule_entities.py +104 -0
  90. zettelforge-2.4.1/tests/test_human_eval_sampler.py +125 -0
  91. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_langchain_retriever.py +5 -1
  92. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_llm_client.py +63 -1
  93. zettelforge-2.4.1/tests/test_sigma_entities.py +205 -0
  94. zettelforge-2.4.1/tests/test_sigma_ingest.py +212 -0
  95. zettelforge-2.4.1/tests/test_sigma_parser.py +125 -0
  96. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_sqlite_backend.py +76 -2
  97. zettelforge-2.4.1/tests/test_telemetry_aggregator.py +142 -0
  98. zettelforge-2.4.1/tests/test_telemetry_collector.py +351 -0
  99. zettelforge-2.4.1/tests/test_telemetry_dashboard.py +238 -0
  100. zettelforge-2.4.1/tests/test_telemetry_integration.py +263 -0
  101. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_two_phase_e2e.py +18 -15
  102. zettelforge-2.4.1/tests/test_yara_entities.py +170 -0
  103. zettelforge-2.4.1/tests/test_yara_ingest.py +126 -0
  104. zettelforge-2.4.1/tests/test_yara_parser.py +126 -0
  105. zettelforge-2.3.0/PKG-INFO +0 -285
  106. zettelforge-2.3.0/README.md +0 -233
  107. zettelforge-2.3.0/docs/assets/logo.svg +0 -3
  108. zettelforge-2.3.0/docs/assets/social-preview.png +0 -0
  109. zettelforge-2.3.0/docs/assets/threatrecall-logo.svg +0 -22
  110. zettelforge-2.3.0/docs/assets/threatrecall-mark.svg +0 -12
  111. zettelforge-2.3.0/docs/assets/zettelforge_architecture.svg +0 -77
  112. zettelforge-2.3.0/docs/stylesheets/extra.css +0 -10
  113. zettelforge-2.3.0/tests/test_causal_extraction.py +0 -91
  114. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/CODEOWNERS +0 -0
  115. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  116. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  117. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/SECURITY.md +0 -0
  118. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/dependabot.yml +0 -0
  119. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/pull_request_template.md +0 -0
  120. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/workflows/ci.yml +0 -0
  121. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/workflows/docs.yml +0 -0
  122. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/workflows/publish.yml +0 -0
  123. {zettelforge-2.3.0 → zettelforge-2.4.1}/.github/workflows/snyk-security.yml +0 -0
  124. {zettelforge-2.3.0 → zettelforge-2.4.1}/.gitignore +0 -0
  125. {zettelforge-2.3.0 → zettelforge-2.4.1}/ARCHITECTURE.md +0 -0
  126. {zettelforge-2.3.0 → zettelforge-2.4.1}/CODEOWNERS +0 -0
  127. {zettelforge-2.3.0 → zettelforge-2.4.1}/CONTRIBUTING.md +0 -0
  128. {zettelforge-2.3.0 → zettelforge-2.4.1}/Dockerfile +0 -0
  129. {zettelforge-2.3.0 → zettelforge-2.4.1}/GOVERNANCE.md +0 -0
  130. {zettelforge-2.3.0 → zettelforge-2.4.1}/LICENSE +0 -0
  131. {zettelforge-2.3.0 → zettelforge-2.4.1}/MANIFEST.in +0 -0
  132. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/BENCHMARK_REPORT.md +0 -0
  133. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
  134. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/auto_ralph.py +0 -0
  135. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/benchmark_harness.py +0 -0
  136. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/cti_benchmark_v2.py +0 -0
  137. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/cti_retrieval_benchmark.py +0 -0
  138. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/cti_retrieval_results.json +0 -0
  139. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/cti_v2_results.json +0 -0
  140. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/ctibench_benchmark.py +0 -0
  141. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/ctibench_results.json +0 -0
  142. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/dataset.json +0 -0
  143. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/enterprise-attack.json +0 -0
  144. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/evolve_benchmark.py +0 -0
  145. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/evolve_results.json +0 -0
  146. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/graph_test.py +0 -0
  147. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/locomo_benchmark.py +0 -0
  148. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/locomo_results.json +0 -0
  149. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
  150. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/memoryagentbench.py +0 -0
  151. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/memoryagentbench_results.json +0 -0
  152. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/mempalace_benchmark.py +0 -0
  153. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/mempalace_results.json +0 -0
  154. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/naive_memory.py +0 -0
  155. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/opencti_benchmark.py +0 -0
  156. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/ragas_benchmark.py +0 -0
  157. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/ragas_cti_results.json +0 -0
  158. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/ragas_results.json +0 -0
  159. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/results/benchmark_report.md +0 -0
  160. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/results/ralph_optimization_log.json +0 -0
  161. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/scale_benchmark.py +0 -0
  162. {zettelforge-2.3.0 → zettelforge-2.4.1}/benchmarks/scale_results.json +0 -0
  163. {zettelforge-2.3.0 → zettelforge-2.4.1}/config.example.yaml +0 -0
  164. {zettelforge-2.3.0 → zettelforge-2.4.1}/docker/docker-compose.yml +0 -0
  165. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/CNAME +0 -0
  166. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/architecture-diagram.mmd +0 -0
  167. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/archive/PACKAGE_SUMMARY.md +0 -0
  168. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/archive/README.md +0 -0
  169. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/archive/SKILL.md +0 -0
  170. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/ZettelForge_Architecture.mmd +0 -0
  171. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/architecture-overview.mmd +0 -0
  172. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/architecture-read-path.mmd +0 -0
  173. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/architecture-write-path.mmd +0 -0
  174. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/demo.gif +0 -0
  175. /zettelforge-2.3.0/docs/assets/favicon.svg → /zettelforge-2.4.1/docs/assets/favicon-old.svg +0 -0
  176. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/threatrecall-logo-philosophy.md +0 -0
  177. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/threatrecall-logo.png +0 -0
  178. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/assets/threatrecall-mark.png +0 -0
  179. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/explanation/architecture.md +0 -0
  180. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/explanation/epistemic-tiers.md +0 -0
  181. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/explanation/stix-in-zettelforge.md +0 -0
  182. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/explanation/two-phase-pipeline.md +0 -0
  183. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/explanation/zettelkasten-philosophy.md +0 -0
  184. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/configure-lancedb.md +0 -0
  185. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/configure-opencti.md +0 -0
  186. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/ingest-news-report.md +0 -0
  187. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/integrate-llm-agent.md +0 -0
  188. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/query-apt-tools.md +0 -0
  189. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/reproduce-benchmarks.md +0 -0
  190. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/resolve-aliases.md +0 -0
  191. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/run-temporal-query.md +0 -0
  192. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/store-threat-actor.md +0 -0
  193. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/how-to/upgrade.md +0 -0
  194. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/llms.txt +0 -0
  195. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/narrative/2026-04-16-the-memory-problem.md +0 -0
  196. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/overrides/main.html +0 -0
  197. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/reference/governance-controls.md +0 -0
  198. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/reference/memory-manager-api.md +0 -0
  199. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/reference/retrieval-policies.md +0 -0
  200. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/reference/stix-schema.md +0 -0
  201. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -0
  202. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/rfcs/RFC-002-universal-llm-provider.md +0 -0
  203. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/rfcs/RFC-003-adversarial-review.md +0 -0
  204. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/rfcs/RFC-003-read-path-depth-routing.md +0 -0
  205. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-ctibench-ragas-benchmarks.md +0 -0
  206. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-fastembed-local-embeddings.md +0 -0
  207. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-hybrid-typedb-lancedb-architecture.md +0 -0
  208. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-local-llm-llama-cpp.md +0 -0
  209. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-anti-aversion-cleanup.md +0 -0
  210. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-causal-graph.md +0 -0
  211. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-ctibench-ate-fix.md +0 -0
  212. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-format-stability.md +0 -0
  213. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-memory-evolution.md +0 -0
  214. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-merge-consolidation.md +0 -0
  215. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-persistence-semantics.md +0 -0
  216. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-sqlite-migration.md +0 -0
  217. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/research/README.md +0 -0
  218. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/superpowers/specs/2026-04-15-p1-features-prd.md +0 -0
  219. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/tutorials/01-quickstart.md +0 -0
  220. {zettelforge-2.3.0 → zettelforge-2.4.1}/docs/tutorials/02-first-cti-report.md +0 -0
  221. {zettelforge-2.3.0 → zettelforge-2.4.1}/examples/athf_bridge.py +0 -0
  222. {zettelforge-2.3.0 → zettelforge-2.4.1}/examples/mcp_claude_code.md +0 -0
  223. {zettelforge-2.3.0 → zettelforge-2.4.1}/examples/quickstart.py +0 -0
  224. {zettelforge-2.3.0 → zettelforge-2.4.1}/governance/controls.yaml +0 -0
  225. {zettelforge-2.3.0 → zettelforge-2.4.1}/scripts/migrate_jsonl_to_sqlite.py +0 -0
  226. {zettelforge-2.3.0 → zettelforge-2.4.1}/scripts/rebuild_index.py +0 -0
  227. {zettelforge-2.3.0 → zettelforge-2.4.1}/scripts/record-demo.sh +0 -0
  228. {zettelforge-2.3.0 → zettelforge-2.4.1}/scripts/typedb-setup.sh +0 -0
  229. {zettelforge-2.3.0 → zettelforge-2.4.1}/scripts/zettelforge-rebuild.service +0 -0
  230. {zettelforge-2.3.0 → zettelforge-2.4.1}/scripts/zettelforge-rebuild.timer +0 -0
  231. {zettelforge-2.3.0 → zettelforge-2.4.1}/skills/claude-code-skill.md +0 -0
  232. {zettelforge-2.3.0 → zettelforge-2.4.1}/skills/openclaw-skill.md +0 -0
  233. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/__main__.py +0 -0
  234. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/alias_resolver.py +0 -0
  235. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/backend_factory.py +0 -0
  236. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/blended_retriever.py +0 -0
  237. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/cache.py +0 -0
  238. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/consolidation.py +0 -0
  239. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/demo.py +0 -0
  240. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/edition.py +0 -0
  241. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/entity_indexer.py +0 -0
  242. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/extensions.py +0 -0
  243. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/fact_extractor.py +0 -0
  244. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/governance_validator.py +0 -0
  245. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/graph_retriever.py +0 -0
  246. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/integrations/__init__.py +0 -0
  247. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/intent_classifier.py +0 -0
  248. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/json_parse.py +0 -0
  249. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/knowledge_graph.py +0 -0
  250. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/llm_client.py +0 -0
  251. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/__init__.py +0 -0
  252. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/base.py +0 -0
  253. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/local_provider.py +0 -0
  254. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/mock_provider.py +0 -0
  255. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/ollama_provider.py +0 -0
  256. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/registry.py +0 -0
  257. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/log.py +0 -0
  258. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/mcp/__init__.py +0 -0
  259. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/mcp/__main__.py +0 -0
  260. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/mcp/server.py +0 -0
  261. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/memory_evolver.py +0 -0
  262. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/memory_store.py +0 -0
  263. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/memory_updater.py +0 -0
  264. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/note_constructor.py +0 -0
  265. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/note_schema.py +0 -0
  266. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/observability.py +0 -0
  267. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/ocsf.py +0 -0
  268. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/retry.py +0 -0
  269. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/synthesis_generator.py +0 -0
  270. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/synthesis_validator.py +0 -0
  271. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/vector_memory.py +0 -0
  272. {zettelforge-2.3.0 → zettelforge-2.4.1}/src/zettelforge/vector_retriever.py +0 -0
  273. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/__init__.py +0 -0
  274. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/benchmark_scale.py +0 -0
  275. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/conftest.py +0 -0
  276. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_basic.py +0 -0
  277. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_blended_retriever.py +0 -0
  278. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_consolidation.py +0 -0
  279. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_cti_integration.py +0 -0
  280. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_edition.py +0 -0
  281. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_embedding.py +0 -0
  282. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_extensions.py +0 -0
  283. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_fact_extractor.py +0 -0
  284. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_governance.py +0 -0
  285. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_governance_spec_drift.py +0 -0
  286. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_graph_retriever.py +0 -0
  287. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_intent_classifier.py +0 -0
  288. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_json_parse.py +0 -0
  289. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_llm_providers.py +0 -0
  290. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_logging_compliance.py +0 -0
  291. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_mcp_server.py +0 -0
  292. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_memory_evolver.py +0 -0
  293. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_memory_updater.py +0 -0
  294. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_performance.py +0 -0
  295. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_recall_integration.py +0 -0
  296. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_sqlite_integration.py +0 -0
  297. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_storage_backend.py +0 -0
  298. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_temporal_graph.py +0 -0
  299. {zettelforge-2.3.0 → zettelforge-2.4.1}/tests/test_typedb_client.py +0 -0
  300. {zettelforge-2.3.0 → zettelforge-2.4.1}/web/app.py +0 -0
  301. {zettelforge-2.3.0 → zettelforge-2.4.1}/web/auth.py +0 -0
  302. {zettelforge-2.3.0 → zettelforge-2.4.1}/web/mcp_server.py +0 -0
@@ -6,6 +6,146 @@ Versioning follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.4.1] - 2026-04-24
10
+
11
+ Operational telemetry (RFC-007), TypeDB authentication hardening, and a
12
+ tranche of SQLite backend correctness fixes surfaced by the sqlite
13
+ review in issue #83.
14
+
15
+ ### Added
16
+
17
+ - **Operational telemetry** (RFC-007, #85) — per-query recall /
18
+ synthesis metrics captured to `~/.amem/telemetry/telemetry_YYYY-MM-DD.jsonl`
19
+ when `ZETTELFORGE_LOG_LEVEL=DEBUG`. Five shipped components:
20
+ - `TelemetryCollector` class (`start_query` / `log_recall` /
21
+ `log_synthesis` / `log_feedback` / `auto_feedback_from_synthesis`)
22
+ with INFO/DEBUG-gated field sets, 1-hour TTL on in-memory query
23
+ context, and thread-safe JSONL append.
24
+ - `MemoryManager` integration — `recall()` and `synthesize()` gain a
25
+ non-breaking `actor=` kwarg; OCSF events extended via the
26
+ sanctioned `unmapped` object with a `zf_` prefix (class_uid 6002
27
+ compliant). `recall()` wraps `retriever.retrieve()` and
28
+ `graph_retriever.retrieve_note_ids()` with narrow-scope
29
+ `perf_counter` deltas for `vector_latency_ms` / `graph_latency_ms`.
30
+ - Daily aggregator (`python -m zettelforge.scripts.telemetry_aggregator`)
31
+ emitting a `DailyMetrics` JSON report (latency averages, tier
32
+ distribution, unused-notes count, top-utility notes).
33
+ - Human-evaluation workflow — 6-question rubric (`docs/human-evaluation-rubric.md`),
34
+ sampler script (`python -m zettelforge.scripts.human_eval_sampler`)
35
+ that selects 20 random briefings as a fill-in Markdown template,
36
+ and a `--write-events` path to append `event_type: "human_eval"`
37
+ entries back to telemetry.
38
+ - Optional Streamlit dashboard (`streamlit run
39
+ src/zettelforge/scripts/telemetry_dashboard.py`) — query volume,
40
+ latency p50/p95/max, tier distribution, utility trend,
41
+ unused-notes warning.
42
+ - Privacy contract: raw note content never persisted (IDs / tiers /
43
+ source_types / domains only); query text truncated at 200 chars
44
+ INFO / 500 chars DEBUG; local-only, no network calls.
45
+
46
+ ### Fixed
47
+
48
+ - **SQLite shutdown NPE** (#84, issue #83 H3) — `close()` and
49
+ `initialize()` are now lock-protected and idempotent. Readers and
50
+ writers raise a clean `BackendClosedError` (new, in
51
+ `storage_backend`) instead of the opaque `AttributeError: 'NoneType'
52
+ object has no attribute 'execute'` seen 170× in production logs on
53
+ 2026-04-23 during atexit. `memory_manager._enrichment_loop` and
54
+ `_drain_enrichment_queue` catch `BackendClosedError` and exit
55
+ cleanly.
56
+ - **SQLite torn snapshot** (#84, issue #83 C1) — `export_snapshot()`
57
+ now uses `sqlite3.Connection.backup()` for a page-consistent copy.
58
+ The previous `shutil.copy2` path could produce a corrupt backup
59
+ missing `-wal` / `-shm` sidecars, unsafe for DR restore.
60
+ - **SQLite reindex race** (#84, issue #83 C2) — `reindex_vector()` now
61
+ uses a single-lock targeted `UPDATE` on the `embedding_vector`
62
+ column. The previous `get_note_by_id → rewrite_note` path spanned
63
+ two lock acquisitions and could clobber concurrent
64
+ `mark_access_dirty` / `evolve` / supersede edits via
65
+ `INSERT OR REPLACE`.
66
+
67
+ ### Security
68
+
69
+ - **TypeDB authentication hardening** (#82) — removed known-insecure
70
+ `admin` / `password` defaults from `TypeDBConfig` and
71
+ `config.default.yaml`. `TypeDBConfig.__repr__` now redacts
72
+ non-empty passwords as `***`. The config loader resolves
73
+ `${TYPEDB_USERNAME}` / `${TYPEDB_PASSWORD}` env-var references in
74
+ YAML (same pattern already used for `llm.api_key`), so secrets can
75
+ stay in env / container secret stores rather than on disk.
76
+ Migration: set `TYPEDB_USERNAME` / `TYPEDB_PASSWORD` in your
77
+ environment or use the `${VAR}` references in a local
78
+ `config.yaml`. Direct env overrides (`TYPEDB_USERNAME=…`) already
79
+ worked and are unaffected.
80
+
81
+ ### Docs
82
+
83
+ - **Architecture Deep Dive + Module Inventory for v2.4.0** (#80) —
84
+ reference-level architecture documentation.
85
+ - **RFC-007 Operational Telemetry** (#85) — full design doc including
86
+ the four subagent-resolved frictions (caller-opt-in query_id
87
+ correlation, narrow-scope latency instrumentation, OCSF unmapped
88
+ extension, hybrid `__new__`-bypass integration tests).
89
+ - **Human Evaluation Rubric** (#85) — 6-question monthly review
90
+ rubric with scoring summary table.
91
+ - **Troubleshoot guide** (#85) — "Operational telemetry" subsection
92
+ covering the three CLI entry points and the privacy contract.
93
+
94
+ ## [2.4.0] - 2026-04-19
95
+
96
+ Detection-rules-as-memory, MCP Registry publication, SQLite concurrency
97
+ hardening, and a full test-suite hygiene pass.
98
+
99
+ ### Added
100
+
101
+ - **Detection rules as first-class memory** (#70) — Sigma and YARA rules
102
+ are now ingested, indexed, and retrieved alongside CTI entities, with
103
+ an LLM rule explainer that surfaces what each rule detects and the
104
+ actors/techniques it's associated with. See the "Detection Rules as
105
+ Memory" section in the README (#74) for usage.
106
+ - **MCP Registry publication** (#75) — `server.json` and the `mcp-name`
107
+ tag required to publish ZettelForge to the canonical MCP Registry
108
+ (registry.modelcontextprotocol.io), which feeds mcp.so and the
109
+ modelcontextprotocol.io community-servers list.
110
+ - **Brand & docs polish** (#61) — neural-chain architecture diagram with
111
+ light/dark parity, updated GitHub social preview, canonical security
112
+ channels + RFC 9116 `security.txt`, real Code of Conduct contacts,
113
+ and a complete brand documentation set.
114
+
115
+ ### Fixed
116
+
117
+ - **SQLite backend concurrency** (#69) — 16 reader methods in
118
+ `SQLiteBackend` (`get_note_by_id`, `get_note_by_source_ref`,
119
+ `iterate_notes`, `get_notes_by_domain`, `get_recent_notes`,
120
+ `count_notes`, `get_kg_node`, `get_kg_node_by_id`,
121
+ `get_kg_neighbors`, `traverse_kg`, `get_entity_timeline`,
122
+ `get_changes_since`, `get_causal_edges`, `get_incoming_causal`,
123
+ `get_note_ids_for_entity`, `search_entities`) were executing
124
+ `SELECT` statements without holding `_write_lock`, while writers
125
+ acquired it. Under concurrent background enrichment, readers could
126
+ observe a partially-written row and raise `pydantic.ValidationError`
127
+ on NULL columns. Each reader now wraps its SQL execute+fetch block
128
+ in `with self._write_lock:` (RLock, reentrant-safe). Closes #68.
129
+ Eliminates the `test_apply_delete_marks_superseded` flake and
130
+ prevents the same race from surfacing in production
131
+ `recall()`-during-write paths.
132
+ - **CI regressions** (#67) — stabilized three tests exposed by the
133
+ test-suite audit sprint.
134
+
135
+ ### Changed
136
+
137
+ - **Test suite hygiene** (#62, #63, #64, #65) — post-v2.3.0 audit (see
138
+ `docs/superpowers/research/2026-04-17-test-suite-audit.md`)
139
+ converted 10 CI-skipped LLM tests to the mock provider (RFC-002
140
+ Phase 1), resolved both remaining `xfail` tests via prompt-routed
141
+ mocks, eliminated two long-standing flakes
142
+ (`test_recall_cve_returns_notes`, `test_apply_delete_marks_superseded`),
143
+ prepped `langchain_retriever` for Pydantic V3 by migrating to
144
+ `ConfigDict`, and reinstated meaningful causal-edge validation via
145
+ mock-seeded triples + `SQLiteBackend.get_causal_edges` query. Net
146
+ test-suite delta: 280 passed / 17 skipped / 2 xfailed → 305 passed
147
+ / 10 skipped / 0 xfailed on test-3.12.
148
+
9
149
  ## [2.3.0] - 2026-04-17
10
150
 
11
151
  Pluggable LLM provider infrastructure (RFC-002 Phase 1), MCP server
@@ -37,7 +37,7 @@ This Code of Conduct applies within all community spaces, and also applies when
37
37
 
38
38
  ## Enforcement
39
39
 
40
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [INSERT CONTACT METHOD]. All complaints will be reviewed and investigated promptly and fairly.
40
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement by email at **conduct@threatrecall.ai**, or privately via GitHub's [report abuse](https://github.com/rolandpg/zettelforge/security/advisories/new) flow. All complaints will be reviewed and investigated promptly and fairly.
41
41
 
42
42
  All community leaders are obligated to respect the privacy and security of the reporter of any incident.
43
43
 
@@ -0,0 +1,324 @@
1
+ Metadata-Version: 2.4
2
+ Name: zettelforge
3
+ Version: 2.4.1
4
+ Summary: ZettelForge: Agentic Memory System with vector search, knowledge graph, and synthesis
5
+ Project-URL: Homepage, https://github.com/rolandpg/zettelforge
6
+ Project-URL: Documentation, https://docs.threatrecall.ai
7
+ Project-URL: Repository, https://github.com/rolandpg/zettelforge
8
+ Project-URL: Issues, https://github.com/rolandpg/zettelforge/issues
9
+ Project-URL: Changelog, https://github.com/rolandpg/zettelforge/blob/master/CHANGELOG.md
10
+ Author-email: Patrick Roland <patrick@groland.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: agentic-memory,ai-agent,cti,cybersecurity,knowledge-graph,llm-memory,mcp-server,rag,stix,threat-intelligence
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Security
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: fastembed>=0.8.0
27
+ Requires-Dist: httpx>=0.25.0
28
+ Requires-Dist: jsonschema>=4.0
29
+ Requires-Dist: lancedb>=0.5.0
30
+ Requires-Dist: numpy>=1.24.0
31
+ Requires-Dist: plyara>=2.0
32
+ Requires-Dist: pyarrow>=14.0.0
33
+ Requires-Dist: pydantic>=2.0.0
34
+ Requires-Dist: pyyaml>=6.0
35
+ Requires-Dist: requests>=2.31.0
36
+ Requires-Dist: structlog>=24.0.0
37
+ Requires-Dist: tantivy>=0.11.0
38
+ Provides-Extra: dev
39
+ Requires-Dist: langchain-core>=0.2.0; extra == 'dev'
40
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
41
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
42
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
43
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
44
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
45
+ Provides-Extra: extensions
46
+ Requires-Dist: zettelforge-enterprise>=2.1.0; extra == 'extensions'
47
+ Provides-Extra: langchain
48
+ Requires-Dist: langchain-core>=0.2.0; extra == 'langchain'
49
+ Provides-Extra: local
50
+ Requires-Dist: llama-cpp-python>=0.3.0; extra == 'local'
51
+ Provides-Extra: web
52
+ Requires-Dist: fastapi>=0.100.0; extra == 'web'
53
+ Requires-Dist: uvicorn>=0.20.0; extra == 'web'
54
+ Description-Content-Type: text/markdown
55
+
56
+ # ZettelForge
57
+
58
+ <!-- mcp-name: io.github.rolandpg/zettelforge -->
59
+
60
+ **The only agentic memory system built for cyber threat intelligence.**
61
+
62
+ When a senior analyst leaves, two or three years of context walks out with them — customer environments, prior investigations, actor TTPs, false-positive patterns, every hard-won "wait, we've seen this before." ZettelForge is an agentic memory system built so that context stays with the team.
63
+
64
+ It extracts CVEs, threat actors, IOCs, and ATT&CK techniques from analyst notes and threat reports, resolves aliases (APT28 = Fancy Bear = STRONTIUM = Sofacy), builds a STIX 2.1 knowledge graph, and serves every past investigation back to your analysts — and to Claude Code via MCP — in natural language. Runs entirely in-process. No API keys. No cloud. No data leaves the host.
65
+
66
+ [![PyPI](https://img.shields.io/pypi/v/zettelforge)](https://pypi.org/project/zettelforge/)
67
+ [![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)
68
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
69
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)
70
+ [![CI](https://github.com/rolandpg/zettelforge/actions/workflows/ci.yml/badge.svg)](https://github.com/rolandpg/zettelforge/actions)
71
+
72
+ **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted beta](https://threatrecall.ai)**
73
+
74
+ <p align="center">
75
+ <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>
76
+ </p>
77
+ <p align="center">
78
+ <img src="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/demo.gif" width="720" alt="ZettelForge demo — CTI agentic memory in action">
79
+ </p>
80
+
81
+ > If ZettelForge fits a CTI workflow you run, a star is the fastest signal that this category is worth continuing to invest in.
82
+
83
+ ## The problem
84
+
85
+ Every SOC loses analysts. When they leave, investigation context, actor attribution, and environment-specific false-positive patterns go with them. Their replacements re-open the same tickets, re-read the same reports, and re-build the same mental models from scratch.
86
+
87
+ 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.
88
+
89
+ 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.
90
+
91
+ >"Memory augmentation closes 33% of the gap between small and large models on CTI tasks (CTI-REALM, Microsoft 2026)." [1]
92
+
93
+ | Capability | ZettelForge | Mem0 | Graphiti | Cognee |
94
+ |---|---|---|---|---|
95
+ | CTI entity extraction (CVEs, actors, IOCs) | Yes | No | No | No |
96
+ | STIX 2.1 ontology | Yes | No | No | No |
97
+ | Threat actor alias resolution | Yes (APT28 = Fancy Bear) | No | No | No |
98
+ | Knowledge graph with causal triples | Yes | No | Yes | Yes |
99
+ | Intent-classified retrieval (5 types) | Yes | No | No | No |
100
+ | In-process / no external API required | Yes | No | No | No |
101
+ | Audit logs in OCSF schema | Yes | No | No | No |
102
+ | MCP server (Claude Code) | Yes | No | No | No |
103
+
104
+ ## Data Pipeline
105
+ <p align="center">
106
+ <picture>
107
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture.svg">
108
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture-light.svg">
109
+ <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">
110
+ </picture>
111
+ </p>
112
+
113
+
114
+ ## Features
115
+
116
+ **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.
117
+
118
+ **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.
119
+
120
+ **Alias Resolution** — APT28, Fancy Bear, Sofacy, STRONTIUM all resolve to the same actor node. Works automatically on store and recall.
121
+
122
+ **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.
123
+
124
+ **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.
125
+
126
+ **RAG Synthesis** — Synthesize answers across all stored memories with `direct_answer` format.
127
+
128
+ **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).
129
+
130
+ **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.
131
+
132
+ ## Quick Start
133
+
134
+ ```bash
135
+ pip install zettelforge
136
+ ```
137
+
138
+ ```python
139
+ from zettelforge import MemoryManager
140
+
141
+ mm = MemoryManager()
142
+
143
+ # Store threat intel — entities extracted automatically
144
+ mm.remember("APT28 uses Cobalt Strike for lateral movement via T1021")
145
+
146
+ # Recall with alias resolution
147
+ results = mm.recall("What tools does Fancy Bear use?")
148
+ # Returns the APT28 note (APT28 = Fancy Bear, resolved automatically)
149
+
150
+ # Synthesize across all memories
151
+ answer = mm.synthesize("Summarize known APT28 TTPs")
152
+ ```
153
+
154
+ No TypeDB, no Ollama, no Docker — just `pip install`. Embeddings run in-process via fastembed. LLM features (extraction, synthesis) activate when Ollama is available.
155
+
156
+ ### With Ollama (enables LLM features)
157
+
158
+ ```bash
159
+ ollama pull qwen2.5:3b && ollama serve
160
+ # ZettelForge auto-detects Ollama for extraction and synthesis
161
+ ```
162
+
163
+ ### Memory Evolution
164
+
165
+ ```python
166
+ # New intel arrives — evolve=True enables memory evolution:
167
+ # LLM extracts facts, compares to existing notes, decides ADD/UPDATE/DELETE/NOOP
168
+ mm.remember(
169
+ "APT28 has shifted tactics. They dropped DROPBEAR and now exploit edge devices.",
170
+ domain="cti",
171
+ evolve=True, # existing APT28 note gets superseded, not duplicated
172
+ )
173
+ ```
174
+
175
+ ## How It Works
176
+
177
+ Every `remember()` call triggers a pipeline:
178
+
179
+ 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)
180
+ 2. **Knowledge Graph Update** — entities become nodes, co-occurrence becomes edges, LLM infers causal triples
181
+ 3. **Vector Embedding** — 768-dim fastembed (ONNX, in-process, 7ms/embed) stored in LanceDB
182
+ 4. **Supersession Check** — entity overlap detection marks stale notes as superseded
183
+ 5. **Dual-Stream Write** — fast path returns in ~45ms; causal enrichment is deferred to a background worker
184
+
185
+ Every `recall()` call blends two retrieval strategies:
186
+
187
+ 1. **Vector similarity** — semantic search over embeddings
188
+ 2. **Graph traversal** — BFS over knowledge graph edges, scored by hop distance
189
+ 3. **Intent routing** — query classified as factual/temporal/relational/causal/exploratory, weights adjusted per type
190
+ 4. **Cross-encoder reranking** — ms-marco-MiniLM reorders final results by relevance
191
+
192
+ ## Benchmarks
193
+
194
+ Evaluated against published academic benchmarks:
195
+
196
+ | Benchmark | What it measures | Score |
197
+ |---|---|---|
198
+ | **CTI Retrieval** | Attribution, CVE linkage, multi-hop | **75.0%** |
199
+ | **RAGAS** | Retrieval quality (keyword presence) | **78.1%** |
200
+ | **LOCOMO** (ACL 2024) | Conversational memory recall | **22.0%** *(with Ollama cloud models)* |
201
+
202
+ See the [full benchmark report](benchmarks/BENCHMARK_REPORT.md) for methodology and analysis.
203
+
204
+ ## MCP Server (Claude Code)
205
+
206
+ Add ZettelForge as a memory backend for Claude Code:
207
+
208
+ ```json
209
+ {
210
+ "mcpServers": {
211
+ "zettelforge": {
212
+ "command": "python3",
213
+ "args": ["-m", "zettelforge.mcp"]
214
+ }
215
+ }
216
+ }
217
+ ```
218
+
219
+ Your Claude Code agent can now remember and recall threat intelligence across sessions.
220
+
221
+ Exposed tools: `remember`, `recall`, `synthesize`, `entity`, `graph`, `stats`.
222
+
223
+ ## Detection Rules as Memory (Sigma + YARA)
224
+
225
+ 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.
226
+
227
+ 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`.
228
+
229
+ ```python
230
+ from zettelforge import MemoryManager
231
+ from zettelforge.sigma import ingest_rule as ingest_sigma
232
+ from zettelforge.yara import ingest_rule as ingest_yara
233
+
234
+ mm = MemoryManager()
235
+ ingest_sigma("rules/proc_creation_win_office_macro.yml", mm)
236
+ ingest_yara("rules/webshell_china_chopper.yar", mm, tier="warn")
237
+ ```
238
+
239
+ ```bash
240
+ # Bulk ingest from SigmaHQ or a private rule repo
241
+ python -m zettelforge.sigma.ingest /path/to/sigma/rules/
242
+ python -m zettelforge.yara.ingest /path/to/yara/rules/ --tier warn
243
+
244
+ # CI fixture check — parse + validate, no writes
245
+ python -m zettelforge.sigma.ingest rules/ --dry-run
246
+ ```
247
+
248
+ 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).
249
+
250
+ 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).
251
+
252
+ ## Integrations
253
+
254
+ ### ATHF (Agentic Threat Hunting Framework)
255
+
256
+ Ingest completed [ATHF](https://github.com/Nebulock-Inc/agentic-threat-hunting-framework) hunts into ZettelForge memory. MITRE techniques and IOCs are extracted and linked in the knowledge graph.
257
+
258
+ ```bash
259
+ python examples/athf_bridge.py /path/to/hunts/
260
+ # 12 hunt(s) parsed
261
+ # Ingested 12/12 hunts into ZettelForge
262
+ ```
263
+
264
+ See [examples/athf_bridge.py](examples/athf_bridge.py).
265
+
266
+
267
+ ## Extensions
268
+
269
+ ZettelForge ships a complete agentic memory core. Everything documented above works from a single `pip install`.
270
+
271
+ For teams that want TypeDB-scale graph storage, OpenCTI integration, or multi-tenant deployment, optional extensions are available:
272
+
273
+ | Extension | What it adds |
274
+ |---|---|
275
+ | TypeDB STIX 2.1 backend | Schema-enforced ontology with inference rules |
276
+ | OpenCTI sync | Bi-directional sync with OpenCTI instances |
277
+ | Multi-tenant auth | OAuth/JWT with per-tenant isolation |
278
+ | Sigma rule generation | Detection rules from extracted IOCs |
279
+
280
+ Extensions install separately:
281
+
282
+ ```bash
283
+ pip install zettelforge-enterprise
284
+ ```
285
+
286
+ **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.
287
+
288
+ ## Configuration
289
+
290
+ | Variable | Default | Description |
291
+ |---|---|---|
292
+ | `AMEM_DATA_DIR` | `~/.amem` | Data directory |
293
+ | `ZETTELFORGE_BACKEND` | `sqlite` | SQLite community backend. TypeDB available via extension. |
294
+ | `ZETTELFORGE_LLM_PROVIDER` | `local` | `local` (llama-cpp) or `ollama` |
295
+
296
+ See [config.default.yaml](config.default.yaml) for all options.
297
+
298
+ ## Contributing
299
+
300
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup.
301
+
302
+ ## License
303
+
304
+ MIT — See [LICENSE](LICENSE).
305
+
306
+ ## About the author
307
+
308
+ 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/).
309
+
310
+ ## Support the Project
311
+
312
+ ZettelForge is MIT-licensed. If it's useful in your workflow and you'd like to help keep it maintained:
313
+
314
+ <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>
315
+
316
+ ## Acknowledgments
317
+
318
+ - Inspired by [Zettelkasten](https://en.wikipedia.org/wiki/Zettelkasten) and [A-Mem](https://arxiv.org/abs/2602.10715) (NeurIPS 2025)
319
+ - Two-phase pipeline inspired by [Mem0](https://mem0.ai/research)
320
+ - STIX 2.1 schema informed by [typedb-cti](https://github.com/typedb-osi/typedb-cti)
321
+ - Benchmarked against [LOCOMO](https://snap-research.github.io/locomo/) (ACL 2024) and [CTIBench](https://arxiv.org/abs/2406.07599) (NeurIPS 2024)
322
+ - [LanceDB](https://lancedb.com) | [fastembed](https://github.com/qdrant/fastembed) | [Pydantic](https://pydantic.dev) | [TypeDB](https://typedb.com)
323
+
324
+ [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/