zettelforge 2.4.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 (293) hide show
  1. {zettelforge-2.4.0 → zettelforge-2.4.1}/CHANGELOG.md +85 -0
  2. {zettelforge-2.4.0 → zettelforge-2.4.1}/PKG-INFO +49 -48
  3. {zettelforge-2.4.0 → zettelforge-2.4.1}/README.md +48 -47
  4. {zettelforge-2.4.0 → zettelforge-2.4.1}/config.default.yaml +5 -2
  5. zettelforge-2.4.1/docs/assets/cf-analytics.js +9 -0
  6. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/configure-typedb.md +6 -4
  7. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/troubleshoot.md +24 -2
  8. zettelforge-2.4.1/docs/human-evaluation-rubric.md +136 -0
  9. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/index.md +10 -4
  10. zettelforge-2.4.1/docs/reference/architecture-deep-dive.md +380 -0
  11. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/reference/configuration.md +4 -4
  12. zettelforge-2.4.1/docs/reference/module-inventory.md +461 -0
  13. zettelforge-2.4.1/docs/rfcs/RFC-007-operational-telemetry.md +321 -0
  14. {zettelforge-2.4.0 → zettelforge-2.4.1}/mkdocs.yml +5 -0
  15. {zettelforge-2.4.0 → zettelforge-2.4.1}/pyproject.toml +1 -1
  16. {zettelforge-2.4.0 → zettelforge-2.4.1}/server.json +1 -1
  17. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/config.py +12 -2
  18. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/memory_manager.py +70 -1
  19. zettelforge-2.4.1/src/zettelforge/scripts/human_eval_sampler.py +175 -0
  20. zettelforge-2.4.1/src/zettelforge/scripts/telemetry_aggregator.py +176 -0
  21. zettelforge-2.4.1/src/zettelforge/scripts/telemetry_dashboard.py +256 -0
  22. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sqlite_backend.py +96 -29
  23. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/storage_backend.py +9 -0
  24. zettelforge-2.4.1/src/zettelforge/telemetry.py +340 -0
  25. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_config.py +53 -0
  26. zettelforge-2.4.1/tests/test_human_eval_sampler.py +125 -0
  27. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_sqlite_backend.py +76 -2
  28. zettelforge-2.4.1/tests/test_telemetry_aggregator.py +142 -0
  29. zettelforge-2.4.1/tests/test_telemetry_collector.py +351 -0
  30. zettelforge-2.4.1/tests/test_telemetry_dashboard.py +238 -0
  31. zettelforge-2.4.1/tests/test_telemetry_integration.py +263 -0
  32. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/CODEOWNERS +0 -0
  33. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  34. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  35. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/SECURITY.md +0 -0
  36. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/dependabot.yml +0 -0
  37. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/pull_request_template.md +0 -0
  38. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/workflows/ci.yml +0 -0
  39. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/workflows/docs.yml +0 -0
  40. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/workflows/publish.yml +0 -0
  41. {zettelforge-2.4.0 → zettelforge-2.4.1}/.github/workflows/snyk-security.yml +0 -0
  42. {zettelforge-2.4.0 → zettelforge-2.4.1}/.gitignore +0 -0
  43. {zettelforge-2.4.0 → zettelforge-2.4.1}/ARCHITECTURE.md +0 -0
  44. {zettelforge-2.4.0 → zettelforge-2.4.1}/CODEOWNERS +0 -0
  45. {zettelforge-2.4.0 → zettelforge-2.4.1}/CODE_OF_CONDUCT.md +0 -0
  46. {zettelforge-2.4.0 → zettelforge-2.4.1}/CONTRIBUTING.md +0 -0
  47. {zettelforge-2.4.0 → zettelforge-2.4.1}/Dockerfile +0 -0
  48. {zettelforge-2.4.0 → zettelforge-2.4.1}/GOVERNANCE.md +0 -0
  49. {zettelforge-2.4.0 → zettelforge-2.4.1}/LICENSE +0 -0
  50. {zettelforge-2.4.0 → zettelforge-2.4.1}/MANIFEST.in +0 -0
  51. {zettelforge-2.4.0 → zettelforge-2.4.1}/SECURITY.md +0 -0
  52. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/BENCHMARK_REPORT.md +0 -0
  53. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
  54. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/auto_ralph.py +0 -0
  55. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/benchmark_harness.py +0 -0
  56. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/cti_benchmark_v2.py +0 -0
  57. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/cti_retrieval_benchmark.py +0 -0
  58. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/cti_retrieval_results.json +0 -0
  59. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/cti_v2_results.json +0 -0
  60. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/ctibench_benchmark.py +0 -0
  61. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/ctibench_results.json +0 -0
  62. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/dataset.json +0 -0
  63. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/enterprise-attack.json +0 -0
  64. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/evolve_benchmark.py +0 -0
  65. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/evolve_results.json +0 -0
  66. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/graph_test.py +0 -0
  67. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/locomo_benchmark.py +0 -0
  68. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/locomo_results.json +0 -0
  69. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
  70. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/memoryagentbench.py +0 -0
  71. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/memoryagentbench_results.json +0 -0
  72. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/mempalace_benchmark.py +0 -0
  73. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/mempalace_results.json +0 -0
  74. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/naive_memory.py +0 -0
  75. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/opencti_benchmark.py +0 -0
  76. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/ragas_benchmark.py +0 -0
  77. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/ragas_cti_results.json +0 -0
  78. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/ragas_results.json +0 -0
  79. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/results/benchmark_report.md +0 -0
  80. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/results/ralph_optimization_log.json +0 -0
  81. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/scale_benchmark.py +0 -0
  82. {zettelforge-2.4.0 → zettelforge-2.4.1}/benchmarks/scale_results.json +0 -0
  83. {zettelforge-2.4.0 → zettelforge-2.4.1}/config.example.yaml +0 -0
  84. {zettelforge-2.4.0 → zettelforge-2.4.1}/docker/docker-compose.yml +0 -0
  85. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/.well-known/security.txt +0 -0
  86. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/CNAME +0 -0
  87. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/architecture-diagram.mmd +0 -0
  88. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/archive/PACKAGE_SUMMARY.md +0 -0
  89. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/archive/README.md +0 -0
  90. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/archive/SKILL.md +0 -0
  91. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/ZettelForge_Architecture.mmd +0 -0
  92. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/architecture-overview.mmd +0 -0
  93. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/architecture-read-path.mmd +0 -0
  94. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/architecture-write-path.mmd +0 -0
  95. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/demo.gif +0 -0
  96. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/favicon-16.png +0 -0
  97. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/favicon-32.png +0 -0
  98. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/favicon-512.png +0 -0
  99. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/favicon-64.png +0 -0
  100. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/favicon-apple-touch.png +0 -0
  101. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/favicon-old.svg +0 -0
  102. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/favicon.svg +0 -0
  103. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/logo.svg +0 -0
  104. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/social-preview.png +0 -0
  105. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/threatrecall-lockup-monogram.svg +0 -0
  106. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/threatrecall-lockup.svg +0 -0
  107. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/threatrecall-logo-flat.svg +0 -0
  108. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/threatrecall-logo-philosophy.md +0 -0
  109. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/threatrecall-logo.png +0 -0
  110. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/threatrecall-mark.png +0 -0
  111. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/zettelforge_architecture-light.svg +0 -0
  112. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/assets/zettelforge_architecture.svg +0 -0
  113. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/brand/brandIdentity.md +0 -0
  114. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/brand/colors_and_type.css +0 -0
  115. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/explanation/architecture.md +0 -0
  116. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/explanation/epistemic-tiers.md +0 -0
  117. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/explanation/stix-in-zettelforge.md +0 -0
  118. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/explanation/two-phase-pipeline.md +0 -0
  119. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/explanation/zettelkasten-philosophy.md +0 -0
  120. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/configure-lancedb.md +0 -0
  121. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/configure-opencti.md +0 -0
  122. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/ingest-news-report.md +0 -0
  123. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/integrate-llm-agent.md +0 -0
  124. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/migrate-jsonl-to-sqlite.md +0 -0
  125. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/query-apt-tools.md +0 -0
  126. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/reproduce-benchmarks.md +0 -0
  127. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/resolve-aliases.md +0 -0
  128. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/run-temporal-query.md +0 -0
  129. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/store-threat-actor.md +0 -0
  130. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/how-to/upgrade.md +0 -0
  131. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/llms.txt +0 -0
  132. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/narrative/2026-04-16-the-memory-problem.md +0 -0
  133. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/overrides/main.html +0 -0
  134. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/reference/governance-controls.md +0 -0
  135. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/reference/memory-manager-api.md +0 -0
  136. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/reference/retrieval-policies.md +0 -0
  137. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/reference/stix-schema.md +0 -0
  138. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -0
  139. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/rfcs/RFC-002-universal-llm-provider.md +0 -0
  140. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/rfcs/RFC-003-adversarial-review.md +0 -0
  141. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/rfcs/RFC-003-read-path-depth-routing.md +0 -0
  142. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/stylesheets/brand-tokens.css +0 -0
  143. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/stylesheets/extra.css +0 -0
  144. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/stylesheets/fonts/Neuropol.otf +0 -0
  145. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-ctibench-ragas-benchmarks.md +0 -0
  146. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-fastembed-local-embeddings.md +0 -0
  147. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-hybrid-typedb-lancedb-architecture.md +0 -0
  148. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-09-local-llm-llama-cpp.md +0 -0
  149. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-anti-aversion-cleanup.md +0 -0
  150. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-causal-graph.md +0 -0
  151. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-ctibench-ate-fix.md +0 -0
  152. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-format-stability.md +0 -0
  153. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-memory-evolution.md +0 -0
  154. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-merge-consolidation.md +0 -0
  155. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-persistence-semantics.md +0 -0
  156. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-15-sqlite-migration.md +0 -0
  157. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/2026-04-17-test-suite-audit.md +0 -0
  158. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/research/README.md +0 -0
  159. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/superpowers/specs/2026-04-15-p1-features-prd.md +0 -0
  160. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/tutorials/01-quickstart.md +0 -0
  161. {zettelforge-2.4.0 → zettelforge-2.4.1}/docs/tutorials/02-first-cti-report.md +0 -0
  162. {zettelforge-2.4.0 → zettelforge-2.4.1}/examples/athf_bridge.py +0 -0
  163. {zettelforge-2.4.0 → zettelforge-2.4.1}/examples/mcp_claude_code.md +0 -0
  164. {zettelforge-2.4.0 → zettelforge-2.4.1}/examples/quickstart.py +0 -0
  165. {zettelforge-2.4.0 → zettelforge-2.4.1}/governance/controls.yaml +0 -0
  166. {zettelforge-2.4.0 → zettelforge-2.4.1}/scripts/migrate_jsonl_to_sqlite.py +0 -0
  167. {zettelforge-2.4.0 → zettelforge-2.4.1}/scripts/rebuild_index.py +0 -0
  168. {zettelforge-2.4.0 → zettelforge-2.4.1}/scripts/record-demo.sh +0 -0
  169. {zettelforge-2.4.0 → zettelforge-2.4.1}/scripts/typedb-setup.sh +0 -0
  170. {zettelforge-2.4.0 → zettelforge-2.4.1}/scripts/zettelforge-rebuild.service +0 -0
  171. {zettelforge-2.4.0 → zettelforge-2.4.1}/scripts/zettelforge-rebuild.timer +0 -0
  172. {zettelforge-2.4.0 → zettelforge-2.4.1}/skills/claude-code-skill.md +0 -0
  173. {zettelforge-2.4.0 → zettelforge-2.4.1}/skills/openclaw-skill.md +0 -0
  174. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/__init__.py +0 -0
  175. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/__main__.py +0 -0
  176. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/alias_resolver.py +0 -0
  177. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/backend_factory.py +0 -0
  178. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/blended_retriever.py +0 -0
  179. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/cache.py +0 -0
  180. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/consolidation.py +0 -0
  181. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/demo.py +0 -0
  182. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/detection/__init__.py +0 -0
  183. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/detection/base.py +0 -0
  184. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/detection/consumers.py +0 -0
  185. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/detection/explainer.py +0 -0
  186. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/edition.py +0 -0
  187. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/entity_indexer.py +0 -0
  188. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/extensions.py +0 -0
  189. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/fact_extractor.py +0 -0
  190. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/governance_validator.py +0 -0
  191. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/graph_retriever.py +0 -0
  192. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/integrations/__init__.py +0 -0
  193. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/integrations/langchain_retriever.py +0 -0
  194. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/intent_classifier.py +0 -0
  195. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/json_parse.py +0 -0
  196. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/knowledge_graph.py +0 -0
  197. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/llm_client.py +0 -0
  198. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/__init__.py +0 -0
  199. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/base.py +0 -0
  200. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/local_provider.py +0 -0
  201. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/mock_provider.py +0 -0
  202. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/ollama_provider.py +0 -0
  203. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/llm_providers/registry.py +0 -0
  204. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/log.py +0 -0
  205. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/mcp/__init__.py +0 -0
  206. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/mcp/__main__.py +0 -0
  207. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/mcp/server.py +0 -0
  208. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/memory_evolver.py +0 -0
  209. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/memory_store.py +0 -0
  210. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/memory_updater.py +0 -0
  211. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/note_constructor.py +0 -0
  212. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/note_schema.py +0 -0
  213. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/observability.py +0 -0
  214. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/ocsf.py +0 -0
  215. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/ontology.py +0 -0
  216. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/retry.py +0 -0
  217. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/__init__.py +0 -0
  218. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/cli.py +0 -0
  219. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/entities.py +0 -0
  220. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/ingest.py +0 -0
  221. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/parser.py +0 -0
  222. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/schemas/NOTICE.md +0 -0
  223. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/schemas/__init__.py +0 -0
  224. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +0 -0
  225. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +0 -0
  226. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/schemas/sigma-filters-schema.json +0 -0
  227. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/sigma/tags.py +0 -0
  228. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/synthesis_generator.py +0 -0
  229. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/synthesis_validator.py +0 -0
  230. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/vector_memory.py +0 -0
  231. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/vector_retriever.py +0 -0
  232. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/__init__.py +0 -0
  233. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/cccs_metadata.py +0 -0
  234. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/cli.py +0 -0
  235. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/entities.py +0 -0
  236. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/ingest.py +0 -0
  237. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/parser.py +0 -0
  238. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/schemas/CCCS_YARA.yml +0 -0
  239. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +0 -0
  240. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/schemas/NOTICE.md +0 -0
  241. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/schemas/__init__.py +0 -0
  242. {zettelforge-2.4.0 → zettelforge-2.4.1}/src/zettelforge/yara/tags.py +0 -0
  243. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/__init__.py +0 -0
  244. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/benchmark_scale.py +0 -0
  245. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/conftest.py +0 -0
  246. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/fixtures/sigma/cloud_example.yml +0 -0
  247. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/fixtures/sigma/correlation_example.yml +0 -0
  248. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/fixtures/sigma/process_creation_example.yml +0 -0
  249. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/fixtures/sigma/tagged_example.yml +0 -0
  250. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/fixtures/yara/malware_hash.yar +0 -0
  251. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/fixtures/yara/technique_loader.yar +0 -0
  252. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/fixtures/yara/webshell.yar +0 -0
  253. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_basic.py +0 -0
  254. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_blended_retriever.py +0 -0
  255. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_causal_extraction.py +0 -0
  256. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_consolidation.py +0 -0
  257. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_conversational_entities.py +0 -0
  258. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_core.py +0 -0
  259. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_cti_integration.py +0 -0
  260. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_detection_explainer.py +0 -0
  261. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_detection_rule_entities.py +0 -0
  262. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_edition.py +0 -0
  263. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_embedding.py +0 -0
  264. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_extensions.py +0 -0
  265. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_fact_extractor.py +0 -0
  266. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_governance.py +0 -0
  267. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_governance_spec_drift.py +0 -0
  268. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_graph_retriever.py +0 -0
  269. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_intent_classifier.py +0 -0
  270. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_json_parse.py +0 -0
  271. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_langchain_retriever.py +0 -0
  272. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_llm_client.py +0 -0
  273. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_llm_providers.py +0 -0
  274. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_logging_compliance.py +0 -0
  275. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_mcp_server.py +0 -0
  276. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_memory_evolver.py +0 -0
  277. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_memory_updater.py +0 -0
  278. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_performance.py +0 -0
  279. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_recall_integration.py +0 -0
  280. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_sigma_entities.py +0 -0
  281. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_sigma_ingest.py +0 -0
  282. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_sigma_parser.py +0 -0
  283. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_sqlite_integration.py +0 -0
  284. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_storage_backend.py +0 -0
  285. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_temporal_graph.py +0 -0
  286. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_two_phase_e2e.py +0 -0
  287. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_typedb_client.py +0 -0
  288. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_yara_entities.py +0 -0
  289. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_yara_ingest.py +0 -0
  290. {zettelforge-2.4.0 → zettelforge-2.4.1}/tests/test_yara_parser.py +0 -0
  291. {zettelforge-2.4.0 → zettelforge-2.4.1}/web/app.py +0 -0
  292. {zettelforge-2.4.0 → zettelforge-2.4.1}/web/auth.py +0 -0
  293. {zettelforge-2.4.0 → zettelforge-2.4.1}/web/mcp_server.py +0 -0
@@ -6,6 +6,91 @@ 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
+
9
94
  ## [2.4.0] - 2026-04-19
10
95
 
11
96
  Detection-rules-as-memory, MCP Registry publication, SQLite concurrency
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zettelforge
3
- Version: 2.4.0
3
+ Version: 2.4.1
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
@@ -59,7 +59,9 @@ Description-Content-Type: text/markdown
59
59
 
60
60
  **The only agentic memory system built for cyber threat intelligence.**
61
61
 
62
- Persistent memory for AI agents and Claude Code with CTI entity extraction, STIX knowledge graphs, threat-actor alias resolution, and offline-first RAG. MCP server included. No cloud, no API keys.
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.
63
65
 
64
66
  [![PyPI](https://img.shields.io/pypi/v/zettelforge)](https://pypi.org/project/zettelforge/)
65
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)
@@ -67,7 +69,7 @@ Persistent memory for AI agents and Claude Code — with CTI entity extraction,
67
69
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)
68
70
  [![CI](https://github.com/rolandpg/zettelforge/actions/workflows/ci.yml/badge.svg)](https://github.com/rolandpg/zettelforge/actions)
69
71
 
70
- **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted](https://threatrecall.ai)**
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)**
71
73
 
72
74
  <p align="center">
73
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>
@@ -78,24 +80,25 @@ Persistent memory for AI agents and Claude Code — with CTI entity extraction,
78
80
 
79
81
  > If ZettelForge fits a CTI workflow you run, a star is the fastest signal that this category is worth continuing to invest in.
80
82
 
81
- ## Why ZettelForge?
83
+ ## The problem
82
84
 
83
- General-purpose memory systems don't understand threat intelligence. They can't tell APT28 from Fancy Bear, don't know that CVE-2024-3094 is the XZ Utils backdoor, and can't track how intelligence evolves across reports. When your agent forgets context between investigations, you end up re-reading the same reports and re-building the same mental models.
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.
84
86
 
85
- ZettelForge was built from the ground up for analysts who think in threat graphs, not chat histories. It extracts CVEs, threat actors, IOCs, and MITRE 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 offline, with no API keys or cloud dependencies.
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.
86
88
 
87
- >"Memory augmentation closes 33% of the gap between small and large models on CTI tasks (CTI-REALM, Microsoft 2026)." [1]
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.
88
90
 
91
+ >"Memory augmentation closes 33% of the gap between small and large models on CTI tasks (CTI-REALM, Microsoft 2026)." [1]
89
92
 
90
- | Feature | ZettelForge | Mem0 | Graphiti | Cognee |
91
- |---------|------------|------|----------|--------|
93
+ | Capability | ZettelForge | Mem0 | Graphiti | Cognee |
94
+ |---|---|---|---|---|
92
95
  | CTI entity extraction (CVEs, actors, IOCs) | Yes | No | No | No |
93
96
  | STIX 2.1 ontology | Yes | No | No | No |
94
97
  | Threat actor alias resolution | Yes (APT28 = Fancy Bear) | No | No | No |
95
98
  | Knowledge graph with causal triples | Yes | No | Yes | Yes |
96
99
  | Intent-classified retrieval (5 types) | Yes | No | No | No |
97
- | Offline / local-first (no API keys) | Yes | No | No | No |
98
- | OCSF audit logging | 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 |
99
102
  | MCP server (Claude Code) | Yes | No | No | No |
100
103
 
101
104
  ## Data Pipeline
@@ -110,21 +113,21 @@ ZettelForge was built from the ground up for analysts who think in threat graphs
110
113
 
111
114
  ## Features
112
115
 
113
- **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.
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.
114
117
 
115
- **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.
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.
116
119
 
117
- **Alias Resolution** -- APT28, Fancy Bear, Sofacy, STRONTIUM all resolve to the same actor node. Works automatically on store and recall.
120
+ **Alias Resolution** APT28, Fancy Bear, Sofacy, STRONTIUM all resolve to the same actor node. Works automatically on store and recall.
118
121
 
119
- **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.
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.
120
123
 
121
- **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.
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.
122
125
 
123
- **RAG Synthesis** -- Synthesize answers across all stored memories with direct_answer format.
126
+ **RAG Synthesis** Synthesize answers across all stored memories with `direct_answer` format.
124
127
 
125
- **Offline-First** -- fastembed (ONNX) for embeddings, llama-cpp-python for LLM features. No API keys, no cloud dependencies.
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).
126
129
 
127
- **OCSF Audit Logging** -- Every operation is logged in OCSF format (FedRAMP AU controls).
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.
128
131
 
129
132
  ## Quick Start
130
133
 
@@ -137,7 +140,7 @@ from zettelforge import MemoryManager
137
140
 
138
141
  mm = MemoryManager()
139
142
 
140
- # Store threat intel -- entities extracted automatically
143
+ # Store threat intel entities extracted automatically
141
144
  mm.remember("APT28 uses Cobalt Strike for lateral movement via T1021")
142
145
 
143
146
  # Recall with alias resolution
@@ -148,7 +151,7 @@ results = mm.recall("What tools does Fancy Bear use?")
148
151
  answer = mm.synthesize("Summarize known APT28 TTPs")
149
152
  ```
150
153
 
151
- No TypeDB, no Ollama, no Docker -- just `pip install`. Embeddings run in-process via fastembed. LLM features (extraction, synthesis) activate when Ollama is available.
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.
152
155
 
153
156
  ### With Ollama (enables LLM features)
154
157
 
@@ -160,7 +163,7 @@ ollama pull qwen2.5:3b && ollama serve
160
163
  ### Memory Evolution
161
164
 
162
165
  ```python
163
- # New intel arrives -- evolve=True enables memory evolution:
166
+ # New intel arrives evolve=True enables memory evolution:
164
167
  # LLM extracts facts, compares to existing notes, decides ADD/UPDATE/DELETE/NOOP
165
168
  mm.remember(
166
169
  "APT28 has shifted tactics. They dropped DROPBEAR and now exploit edge devices.",
@@ -173,25 +176,25 @@ mm.remember(
173
176
 
174
177
  Every `remember()` call triggers a pipeline:
175
178
 
176
- 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)
177
- 2. **Knowledge Graph Update** -- entities become nodes, co-occurrence becomes edges, LLM infers causal triples
178
- 3. **Vector Embedding** -- 768-dim fastembed (ONNX, in-process, 7ms/embed) stored in LanceDB
179
- 4. **Supersession Check** -- entity overlap detection marks stale notes as superseded
180
- 5. **Dual-Stream Write** -- fast path returns in ~45ms; causal enrichment is deferred to a background worker
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
181
184
 
182
185
  Every `recall()` call blends two retrieval strategies:
183
186
 
184
- 1. **Vector similarity** -- semantic search over embeddings
185
- 2. **Graph traversal** -- BFS over knowledge graph edges, scored by hop distance
186
- 3. **Intent routing** -- query classified as factual/temporal/relational/causal/exploratory, weights adjusted per type
187
- 4. **Cross-encoder reranking** -- ms-marco-MiniLM reorders final results by relevance
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
188
191
 
189
192
  ## Benchmarks
190
193
 
191
194
  Evaluated against published academic benchmarks:
192
195
 
193
196
  | Benchmark | What it measures | Score |
194
- |-----------|-----------------|-------|
197
+ |---|---|---|
195
198
  | **CTI Retrieval** | Attribution, CVE linkage, multi-hop | **75.0%** |
196
199
  | **RAGAS** | Retrieval quality (keyword presence) | **78.1%** |
197
200
  | **LOCOMO** (ACL 2024) | Conversational memory recall | **22.0%** *(with Ollama cloud models)* |
@@ -221,7 +224,7 @@ Exposed tools: `remember`, `recall`, `synthesize`, `entity`, `graph`, `stats`.
221
224
 
222
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.
223
226
 
224
- Sigma rules are validated against the vendored [SigmaHQ JSON schema](https://github.com/SigmaHQ/sigma-specification). YARA rules are parsed with plyara and validated 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`.
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`.
225
228
 
226
229
  ```python
227
230
  from zettelforge import MemoryManager
@@ -238,11 +241,11 @@ ingest_yara("rules/webshell_china_chopper.yar", mm, tier="warn")
238
241
  python -m zettelforge.sigma.ingest /path/to/sigma/rules/
239
242
  python -m zettelforge.yara.ingest /path/to/yara/rules/ --tier warn
240
243
 
241
- # CI fixture check -- parse + validate, no writes
244
+ # CI fixture check parse + validate, no writes
242
245
  python -m zettelforge.sigma.ingest rules/ --dry-run
243
246
  ```
244
247
 
245
- 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).
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).
246
249
 
247
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).
248
251
 
@@ -263,35 +266,31 @@ See [examples/athf_bridge.py](examples/athf_bridge.py).
263
266
 
264
267
  ## Extensions
265
268
 
266
- ZettelForge is a complete, production-ready agentic memory system.
267
- Everything documented above works out of the box.
269
+ ZettelForge ships a complete agentic memory core. Everything documented above works from a single `pip install`.
268
270
 
269
- For teams that need TypeDB-scale graph storage, OpenCTI integration,
270
- or multi-tenant deployment, optional extensions are available:
271
+ For teams that want TypeDB-scale graph storage, OpenCTI integration, or multi-tenant deployment, optional extensions are available:
271
272
 
272
273
  | Extension | What it adds |
273
- |-----------|-------------|
274
+ |---|---|
274
275
  | TypeDB STIX 2.1 backend | Schema-enforced ontology with inference rules |
275
276
  | OpenCTI sync | Bi-directional sync with OpenCTI instances |
276
277
  | Multi-tenant auth | OAuth/JWT with per-tenant isolation |
277
278
  | Sigma rule generation | Detection rules from extracted IOCs |
278
279
 
279
- Extensions are installed separately:
280
+ Extensions install separately:
280
281
 
281
282
  ```bash
282
283
  pip install zettelforge-enterprise
283
284
  ```
284
285
 
285
- **Hosted option:** [ThreatRecall](https://threatrecall.ai) provides
286
- managed ZettelForge with all extensions, so you don't have to run
287
- infrastructure yourself.
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.
288
287
 
289
288
  ## Configuration
290
289
 
291
290
  | Variable | Default | Description |
292
- |----------|---------|-------------|
291
+ |---|---|---|
293
292
  | `AMEM_DATA_DIR` | `~/.amem` | Data directory |
294
- | `ZETTELFORGE_BACKEND` | `sqlite` | SQLite community backend. TypeDB is available via extension. |
293
+ | `ZETTELFORGE_BACKEND` | `sqlite` | SQLite community backend. TypeDB available via extension. |
295
294
  | `ZETTELFORGE_LLM_PROVIDER` | `local` | `local` (llama-cpp) or `ollama` |
296
295
 
297
296
  See [config.default.yaml](config.default.yaml) for all options.
@@ -302,9 +301,11 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup.
302
301
 
303
302
  ## License
304
303
 
305
- MIT -- See [LICENSE](LICENSE).
304
+ MIT See [LICENSE](LICENSE).
305
+
306
+ ## About the author
306
307
 
307
- **Made by Patrick Roland**.
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/).
308
309
 
309
310
  ## Support the Project
310
311
 
@@ -4,7 +4,9 @@
4
4
 
5
5
  **The only agentic memory system built for cyber threat intelligence.**
6
6
 
7
- Persistent memory for AI agents and Claude Code with CTI entity extraction, STIX knowledge graphs, threat-actor alias resolution, and offline-first RAG. MCP server included. No cloud, no API keys.
7
+ 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.
8
+
9
+ 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.
8
10
 
9
11
  [![PyPI](https://img.shields.io/pypi/v/zettelforge)](https://pypi.org/project/zettelforge/)
10
12
  [![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)
@@ -12,7 +14,7 @@ Persistent memory for AI agents and Claude Code — with CTI entity extraction,
12
14
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)
13
15
  [![CI](https://github.com/rolandpg/zettelforge/actions/workflows/ci.yml/badge.svg)](https://github.com/rolandpg/zettelforge/actions)
14
16
 
15
- **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted](https://threatrecall.ai)**
17
+ **[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted beta](https://threatrecall.ai)**
16
18
 
17
19
  <p align="center">
18
20
  <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>
@@ -23,24 +25,25 @@ Persistent memory for AI agents and Claude Code — with CTI entity extraction,
23
25
 
24
26
  > If ZettelForge fits a CTI workflow you run, a star is the fastest signal that this category is worth continuing to invest in.
25
27
 
26
- ## Why ZettelForge?
28
+ ## The problem
27
29
 
28
- General-purpose memory systems don't understand threat intelligence. They can't tell APT28 from Fancy Bear, don't know that CVE-2024-3094 is the XZ Utils backdoor, and can't track how intelligence evolves across reports. When your agent forgets context between investigations, you end up re-reading the same reports and re-building the same mental models.
30
+ 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.
29
31
 
30
- ZettelForge was built from the ground up for analysts who think in threat graphs, not chat histories. It extracts CVEs, threat actors, IOCs, and MITRE 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 offline, with no API keys or cloud dependencies.
32
+ 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.
31
33
 
32
- >"Memory augmentation closes 33% of the gap between small and large models on CTI tasks (CTI-REALM, Microsoft 2026)." [1]
34
+ 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.
33
35
 
36
+ >"Memory augmentation closes 33% of the gap between small and large models on CTI tasks (CTI-REALM, Microsoft 2026)." [1]
34
37
 
35
- | Feature | ZettelForge | Mem0 | Graphiti | Cognee |
36
- |---------|------------|------|----------|--------|
38
+ | Capability | ZettelForge | Mem0 | Graphiti | Cognee |
39
+ |---|---|---|---|---|
37
40
  | CTI entity extraction (CVEs, actors, IOCs) | Yes | No | No | No |
38
41
  | STIX 2.1 ontology | Yes | No | No | No |
39
42
  | Threat actor alias resolution | Yes (APT28 = Fancy Bear) | No | No | No |
40
43
  | Knowledge graph with causal triples | Yes | No | Yes | Yes |
41
44
  | Intent-classified retrieval (5 types) | Yes | No | No | No |
42
- | Offline / local-first (no API keys) | Yes | No | No | No |
43
- | OCSF audit logging | Yes | No | No | No |
45
+ | In-process / no external API required | Yes | No | No | No |
46
+ | Audit logs in OCSF schema | Yes | No | No | No |
44
47
  | MCP server (Claude Code) | Yes | No | No | No |
45
48
 
46
49
  ## Data Pipeline
@@ -55,21 +58,21 @@ ZettelForge was built from the ground up for analysts who think in threat graphs
55
58
 
56
59
  ## Features
57
60
 
58
- **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.
61
+ **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.
59
62
 
60
- **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.
63
+ **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.
61
64
 
62
- **Alias Resolution** -- APT28, Fancy Bear, Sofacy, STRONTIUM all resolve to the same actor node. Works automatically on store and recall.
65
+ **Alias Resolution** APT28, Fancy Bear, Sofacy, STRONTIUM all resolve to the same actor node. Works automatically on store and recall.
63
66
 
64
- **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.
67
+ **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.
65
68
 
66
- **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.
69
+ **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.
67
70
 
68
- **RAG Synthesis** -- Synthesize answers across all stored memories with direct_answer format.
71
+ **RAG Synthesis** Synthesize answers across all stored memories with `direct_answer` format.
69
72
 
70
- **Offline-First** -- fastembed (ONNX) for embeddings, llama-cpp-python for LLM features. No API keys, no cloud dependencies.
73
+ **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).
71
74
 
72
- **OCSF Audit Logging** -- Every operation is logged in OCSF format (FedRAMP AU controls).
75
+ **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.
73
76
 
74
77
  ## Quick Start
75
78
 
@@ -82,7 +85,7 @@ from zettelforge import MemoryManager
82
85
 
83
86
  mm = MemoryManager()
84
87
 
85
- # Store threat intel -- entities extracted automatically
88
+ # Store threat intel entities extracted automatically
86
89
  mm.remember("APT28 uses Cobalt Strike for lateral movement via T1021")
87
90
 
88
91
  # Recall with alias resolution
@@ -93,7 +96,7 @@ results = mm.recall("What tools does Fancy Bear use?")
93
96
  answer = mm.synthesize("Summarize known APT28 TTPs")
94
97
  ```
95
98
 
96
- No TypeDB, no Ollama, no Docker -- just `pip install`. Embeddings run in-process via fastembed. LLM features (extraction, synthesis) activate when Ollama is available.
99
+ No TypeDB, no Ollama, no Docker just `pip install`. Embeddings run in-process via fastembed. LLM features (extraction, synthesis) activate when Ollama is available.
97
100
 
98
101
  ### With Ollama (enables LLM features)
99
102
 
@@ -105,7 +108,7 @@ ollama pull qwen2.5:3b && ollama serve
105
108
  ### Memory Evolution
106
109
 
107
110
  ```python
108
- # New intel arrives -- evolve=True enables memory evolution:
111
+ # New intel arrives evolve=True enables memory evolution:
109
112
  # LLM extracts facts, compares to existing notes, decides ADD/UPDATE/DELETE/NOOP
110
113
  mm.remember(
111
114
  "APT28 has shifted tactics. They dropped DROPBEAR and now exploit edge devices.",
@@ -118,25 +121,25 @@ mm.remember(
118
121
 
119
122
  Every `remember()` call triggers a pipeline:
120
123
 
121
- 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)
122
- 2. **Knowledge Graph Update** -- entities become nodes, co-occurrence becomes edges, LLM infers causal triples
123
- 3. **Vector Embedding** -- 768-dim fastembed (ONNX, in-process, 7ms/embed) stored in LanceDB
124
- 4. **Supersession Check** -- entity overlap detection marks stale notes as superseded
125
- 5. **Dual-Stream Write** -- fast path returns in ~45ms; causal enrichment is deferred to a background worker
124
+ 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)
125
+ 2. **Knowledge Graph Update** entities become nodes, co-occurrence becomes edges, LLM infers causal triples
126
+ 3. **Vector Embedding** 768-dim fastembed (ONNX, in-process, 7ms/embed) stored in LanceDB
127
+ 4. **Supersession Check** entity overlap detection marks stale notes as superseded
128
+ 5. **Dual-Stream Write** fast path returns in ~45ms; causal enrichment is deferred to a background worker
126
129
 
127
130
  Every `recall()` call blends two retrieval strategies:
128
131
 
129
- 1. **Vector similarity** -- semantic search over embeddings
130
- 2. **Graph traversal** -- BFS over knowledge graph edges, scored by hop distance
131
- 3. **Intent routing** -- query classified as factual/temporal/relational/causal/exploratory, weights adjusted per type
132
- 4. **Cross-encoder reranking** -- ms-marco-MiniLM reorders final results by relevance
132
+ 1. **Vector similarity** semantic search over embeddings
133
+ 2. **Graph traversal** BFS over knowledge graph edges, scored by hop distance
134
+ 3. **Intent routing** query classified as factual/temporal/relational/causal/exploratory, weights adjusted per type
135
+ 4. **Cross-encoder reranking** ms-marco-MiniLM reorders final results by relevance
133
136
 
134
137
  ## Benchmarks
135
138
 
136
139
  Evaluated against published academic benchmarks:
137
140
 
138
141
  | Benchmark | What it measures | Score |
139
- |-----------|-----------------|-------|
142
+ |---|---|---|
140
143
  | **CTI Retrieval** | Attribution, CVE linkage, multi-hop | **75.0%** |
141
144
  | **RAGAS** | Retrieval quality (keyword presence) | **78.1%** |
142
145
  | **LOCOMO** (ACL 2024) | Conversational memory recall | **22.0%** *(with Ollama cloud models)* |
@@ -166,7 +169,7 @@ Exposed tools: `remember`, `recall`, `synthesize`, `entity`, `graph`, `stats`.
166
169
 
167
170
  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.
168
171
 
169
- Sigma rules are validated against the vendored [SigmaHQ JSON schema](https://github.com/SigmaHQ/sigma-specification). YARA rules are parsed with plyara and validated 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`.
172
+ 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`.
170
173
 
171
174
  ```python
172
175
  from zettelforge import MemoryManager
@@ -183,11 +186,11 @@ ingest_yara("rules/webshell_china_chopper.yar", mm, tier="warn")
183
186
  python -m zettelforge.sigma.ingest /path/to/sigma/rules/
184
187
  python -m zettelforge.yara.ingest /path/to/yara/rules/ --tier warn
185
188
 
186
- # CI fixture check -- parse + validate, no writes
189
+ # CI fixture check parse + validate, no writes
187
190
  python -m zettelforge.sigma.ingest rules/ --dry-run
188
191
  ```
189
192
 
190
- 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).
193
+ 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).
191
194
 
192
195
  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).
193
196
 
@@ -208,35 +211,31 @@ See [examples/athf_bridge.py](examples/athf_bridge.py).
208
211
 
209
212
  ## Extensions
210
213
 
211
- ZettelForge is a complete, production-ready agentic memory system.
212
- Everything documented above works out of the box.
214
+ ZettelForge ships a complete agentic memory core. Everything documented above works from a single `pip install`.
213
215
 
214
- For teams that need TypeDB-scale graph storage, OpenCTI integration,
215
- or multi-tenant deployment, optional extensions are available:
216
+ For teams that want TypeDB-scale graph storage, OpenCTI integration, or multi-tenant deployment, optional extensions are available:
216
217
 
217
218
  | Extension | What it adds |
218
- |-----------|-------------|
219
+ |---|---|
219
220
  | TypeDB STIX 2.1 backend | Schema-enforced ontology with inference rules |
220
221
  | OpenCTI sync | Bi-directional sync with OpenCTI instances |
221
222
  | Multi-tenant auth | OAuth/JWT with per-tenant isolation |
222
223
  | Sigma rule generation | Detection rules from extracted IOCs |
223
224
 
224
- Extensions are installed separately:
225
+ Extensions install separately:
225
226
 
226
227
  ```bash
227
228
  pip install zettelforge-enterprise
228
229
  ```
229
230
 
230
- **Hosted option:** [ThreatRecall](https://threatrecall.ai) provides
231
- managed ZettelForge with all extensions, so you don't have to run
232
- infrastructure yourself.
231
+ **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.
233
232
 
234
233
  ## Configuration
235
234
 
236
235
  | Variable | Default | Description |
237
- |----------|---------|-------------|
236
+ |---|---|---|
238
237
  | `AMEM_DATA_DIR` | `~/.amem` | Data directory |
239
- | `ZETTELFORGE_BACKEND` | `sqlite` | SQLite community backend. TypeDB is available via extension. |
238
+ | `ZETTELFORGE_BACKEND` | `sqlite` | SQLite community backend. TypeDB available via extension. |
240
239
  | `ZETTELFORGE_LLM_PROVIDER` | `local` | `local` (llama-cpp) or `ollama` |
241
240
 
242
241
  See [config.default.yaml](config.default.yaml) for all options.
@@ -247,9 +246,11 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup.
247
246
 
248
247
  ## License
249
248
 
250
- MIT -- See [LICENSE](LICENSE).
249
+ MIT See [LICENSE](LICENSE).
250
+
251
+ ## About the author
251
252
 
252
- **Made by Patrick Roland**.
253
+ 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/).
253
254
 
254
255
  ## Support the Project
255
256
 
@@ -54,6 +54,9 @@ storage:
54
54
  # host: zettelforge-typedb.eastus2.azurecontainer.io
55
55
  # port: 1729
56
56
  #
57
+ # Credentials are required when using the TypeDB backend. Supply them via
58
+ # environment variables — never commit plaintext secrets to version control.
59
+ #
57
60
  # Env overrides:
58
61
  # TYPEDB_HOST=db.internal
59
62
  # TYPEDB_PORT=1729
@@ -65,8 +68,8 @@ typedb:
65
68
  host: localhost
66
69
  port: 1729
67
70
  database: zettelforge
68
- username: admin
69
- password: password
71
+ username: ${TYPEDB_USERNAME}
72
+ password: ${TYPEDB_PASSWORD}
70
73
 
71
74
 
72
75
  # ── Storage Backend ────────────────────────────────────────────────────────
@@ -0,0 +1,9 @@
1
+ // Cloudflare Web Analytics — docs.threatrecall.ai
2
+ // Injected via mkdocs.yml extra_javascript.
3
+ (function(){
4
+ var s = document.createElement('script');
5
+ s.defer = true;
6
+ s.src = 'https://static.cloudflareinsights.com/beacon.min.js';
7
+ s.setAttribute('data-cf-beacon', '{"token": "7740fa0d6ecf41abb3c7bc06803e7ed3"}');
8
+ document.head.appendChild(s);
9
+ })();
@@ -103,14 +103,14 @@ typedb:
103
103
  host: localhost
104
104
  port: 1729
105
105
  database: zettelforge
106
- username: admin
107
- password: password
106
+ username: ${TYPEDB_USERNAME}
107
+ password: ${TYPEDB_PASSWORD}
108
108
 
109
109
  backend: typedb
110
110
  ```
111
111
 
112
- > [!TIP]
113
- > `config.yaml` is in `.gitignore`. Safe for credentials. Environment variables override config file values.
112
+ > [!IMPORTANT]
113
+ > TypeDB credentials must be supplied via environment variables. `config.yaml` is in `.gitignore` so it is safe for local overrides, but the preferred approach is to set `TYPEDB_USERNAME` and `TYPEDB_PASSWORD` in your shell or container environment rather than writing them into any config file.
114
114
 
115
115
  ### 6. Override with environment variables (optional)
116
116
 
@@ -118,6 +118,8 @@ backend: typedb
118
118
  export TYPEDB_HOST=localhost
119
119
  export TYPEDB_PORT=1729
120
120
  export TYPEDB_DATABASE=zettelforge
121
+ export TYPEDB_USERNAME=admin
122
+ export TYPEDB_PASSWORD=<your-password>
121
123
  export ZETTELFORGE_BACKEND=typedb
122
124
  ```
123
125