zettelforge 2.2.0__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/workflows/ci.yml +2 -1
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/workflows/docs.yml +2 -2
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.gitignore +4 -1
- zettelforge-2.4.0/ARCHITECTURE.md +42 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/CHANGELOG.md +198 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/CODE_OF_CONDUCT.md +1 -1
- {zettelforge-2.2.0 → zettelforge-2.4.0}/PKG-INFO +75 -33
- {zettelforge-2.2.0 → zettelforge-2.4.0}/README.md +64 -29
- {zettelforge-2.2.0 → zettelforge-2.4.0}/SECURITY.md +38 -11
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/BENCHMARK_REPORT.md +45 -19
- {zettelforge-2.2.0 → zettelforge-2.4.0}/config.default.yaml +49 -17
- zettelforge-2.4.0/docs/.well-known/security.txt +10 -0
- zettelforge-2.4.0/docs/architecture-diagram.mmd +202 -0
- zettelforge-2.4.0/docs/archive/README.md +11 -0
- zettelforge-2.4.0/docs/assets/ZettelForge_Architecture.mmd +185 -0
- zettelforge-2.4.0/docs/assets/architecture-overview.mmd +57 -0
- zettelforge-2.4.0/docs/assets/architecture-read-path.mmd +140 -0
- zettelforge-2.4.0/docs/assets/architecture-write-path.mmd +122 -0
- zettelforge-2.4.0/docs/assets/favicon-16.png +0 -0
- zettelforge-2.4.0/docs/assets/favicon-32.png +0 -0
- zettelforge-2.4.0/docs/assets/favicon-512.png +0 -0
- zettelforge-2.4.0/docs/assets/favicon-64.png +0 -0
- zettelforge-2.4.0/docs/assets/favicon-apple-touch.png +0 -0
- zettelforge-2.4.0/docs/assets/favicon.svg +33 -0
- zettelforge-2.4.0/docs/assets/logo.svg +46 -0
- zettelforge-2.4.0/docs/assets/social-preview.png +0 -0
- zettelforge-2.4.0/docs/assets/threatrecall-lockup-monogram.svg +41 -0
- zettelforge-2.4.0/docs/assets/threatrecall-lockup.svg +39 -0
- zettelforge-2.4.0/docs/assets/threatrecall-logo-flat.svg +29 -0
- zettelforge-2.4.0/docs/assets/zettelforge_architecture-light.svg +105 -0
- zettelforge-2.4.0/docs/assets/zettelforge_architecture.svg +105 -0
- zettelforge-2.4.0/docs/brand/brandIdentity.md +266 -0
- zettelforge-2.4.0/docs/brand/colors_and_type.css +286 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/explanation/architecture.md +1 -1
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/explanation/stix-in-zettelforge.md +1 -1
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/integrate-llm-agent.md +1 -1
- zettelforge-2.4.0/docs/how-to/migrate-jsonl-to-sqlite.md +114 -0
- zettelforge-2.4.0/docs/how-to/reproduce-benchmarks.md +120 -0
- zettelforge-2.4.0/docs/how-to/troubleshoot.md +180 -0
- zettelforge-2.4.0/docs/how-to/upgrade.md +94 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/index.md +4 -4
- zettelforge-2.4.0/docs/llms.txt +64 -0
- zettelforge-2.4.0/docs/narrative/2026-04-16-the-memory-problem.md +86 -0
- zettelforge-2.4.0/docs/overrides/main.html +82 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/reference/configuration.md +39 -10
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/reference/governance-controls.md +2 -2
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/reference/memory-manager-api.md +1 -1
- zettelforge-2.4.0/docs/rfcs/RFC-001-conversational-entity-extractor.md +356 -0
- zettelforge-2.4.0/docs/rfcs/RFC-002-universal-llm-provider.md +883 -0
- zettelforge-2.4.0/docs/rfcs/RFC-003-adversarial-review.md +393 -0
- zettelforge-2.4.0/docs/rfcs/RFC-003-read-path-depth-routing.md +936 -0
- zettelforge-2.4.0/docs/stylesheets/brand-tokens.css +158 -0
- zettelforge-2.4.0/docs/stylesheets/extra.css +70 -0
- zettelforge-2.4.0/docs/stylesheets/fonts/Neuropol.otf +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-15-causal-graph.md +36 -0
- zettelforge-2.4.0/docs/superpowers/research/2026-04-15-format-stability.md +1029 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-15-memory-evolution.md +41 -1
- zettelforge-2.4.0/docs/superpowers/research/2026-04-15-merge-consolidation.md +372 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-15-persistence-semantics.md +50 -0
- zettelforge-2.4.0/docs/superpowers/research/2026-04-17-test-suite-audit.md +178 -0
- zettelforge-2.4.0/docs/superpowers/research/README.md +40 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/superpowers/specs/2026-04-15-p1-features-prd.md +197 -29
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/tutorials/01-quickstart.md +3 -3
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/tutorials/02-first-cti-report.md +2 -2
- {zettelforge-2.2.0 → zettelforge-2.4.0}/mkdocs.yml +32 -2
- {zettelforge-2.2.0 → zettelforge-2.4.0}/pyproject.toml +16 -4
- zettelforge-2.4.0/server.json +21 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/__init__.py +14 -10
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/backend_factory.py +21 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/cache.py +7 -3
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/config.py +117 -6
- zettelforge-2.4.0/src/zettelforge/detection/__init__.py +24 -0
- zettelforge-2.4.0/src/zettelforge/detection/base.py +63 -0
- zettelforge-2.4.0/src/zettelforge/detection/consumers.py +77 -0
- zettelforge-2.4.0/src/zettelforge/detection/explainer.py +320 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/entity_indexer.py +11 -3
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/integrations/langchain_retriever.py +3 -6
- zettelforge-2.4.0/src/zettelforge/llm_client.py +287 -0
- zettelforge-2.4.0/src/zettelforge/llm_providers/__init__.py +84 -0
- zettelforge-2.4.0/src/zettelforge/llm_providers/base.py +59 -0
- zettelforge-2.4.0/src/zettelforge/llm_providers/local_provider.py +96 -0
- zettelforge-2.4.0/src/zettelforge/llm_providers/mock_provider.py +50 -0
- zettelforge-2.4.0/src/zettelforge/llm_providers/ollama_provider.py +56 -0
- zettelforge-2.4.0/src/zettelforge/llm_providers/registry.py +76 -0
- zettelforge-2.4.0/src/zettelforge/mcp/__init__.py +34 -0
- zettelforge-2.4.0/src/zettelforge/mcp/__main__.py +11 -0
- zettelforge-2.2.0/web/mcp_server.py → zettelforge-2.4.0/src/zettelforge/mcp/server.py +30 -40
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/memory_manager.py +107 -3
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/observability.py +8 -3
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/ocsf.py +15 -1
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/ontology.py +129 -4
- zettelforge-2.4.0/src/zettelforge/sigma/__init__.py +31 -0
- zettelforge-2.4.0/src/zettelforge/sigma/cli.py +123 -0
- zettelforge-2.4.0/src/zettelforge/sigma/entities.py +249 -0
- zettelforge-2.4.0/src/zettelforge/sigma/ingest.py +234 -0
- zettelforge-2.4.0/src/zettelforge/sigma/parser.py +148 -0
- zettelforge-2.4.0/src/zettelforge/sigma/schemas/NOTICE.md +10 -0
- zettelforge-2.4.0/src/zettelforge/sigma/schemas/__init__.py +1 -0
- zettelforge-2.4.0/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +326 -0
- zettelforge-2.4.0/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +247 -0
- zettelforge-2.4.0/src/zettelforge/sigma/schemas/sigma-filters-schema.json +101 -0
- zettelforge-2.4.0/src/zettelforge/sigma/tags.py +86 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/sqlite_backend.py +157 -125
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/vector_retriever.py +12 -2
- zettelforge-2.4.0/src/zettelforge/yara/__init__.py +27 -0
- zettelforge-2.4.0/src/zettelforge/yara/cccs_metadata.py +258 -0
- zettelforge-2.4.0/src/zettelforge/yara/cli.py +177 -0
- zettelforge-2.4.0/src/zettelforge/yara/entities.py +269 -0
- zettelforge-2.4.0/src/zettelforge/yara/ingest.py +327 -0
- zettelforge-2.4.0/src/zettelforge/yara/parser.py +110 -0
- zettelforge-2.4.0/src/zettelforge/yara/schemas/CCCS_YARA.yml +306 -0
- zettelforge-2.4.0/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +160 -0
- zettelforge-2.4.0/src/zettelforge/yara/schemas/NOTICE.md +11 -0
- zettelforge-2.4.0/src/zettelforge/yara/schemas/__init__.py +1 -0
- zettelforge-2.4.0/src/zettelforge/yara/tags.py +74 -0
- zettelforge-2.4.0/tests/fixtures/sigma/cloud_example.yml +20 -0
- zettelforge-2.4.0/tests/fixtures/sigma/correlation_example.yml +14 -0
- zettelforge-2.4.0/tests/fixtures/sigma/process_creation_example.yml +17 -0
- zettelforge-2.4.0/tests/fixtures/sigma/tagged_example.yml +30 -0
- zettelforge-2.4.0/tests/fixtures/yara/malware_hash.yar +19 -0
- zettelforge-2.4.0/tests/fixtures/yara/technique_loader.yar +23 -0
- zettelforge-2.4.0/tests/fixtures/yara/webshell.yar +19 -0
- zettelforge-2.4.0/tests/test_causal_extraction.py +102 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_conversational_entities.py +50 -11
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_core.py +6 -5
- zettelforge-2.4.0/tests/test_detection_explainer.py +328 -0
- zettelforge-2.4.0/tests/test_detection_rule_entities.py +104 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_langchain_retriever.py +18 -7
- zettelforge-2.4.0/tests/test_llm_client.py +158 -0
- zettelforge-2.4.0/tests/test_llm_providers.py +318 -0
- zettelforge-2.4.0/tests/test_mcp_server.py +139 -0
- zettelforge-2.4.0/tests/test_sigma_entities.py +205 -0
- zettelforge-2.4.0/tests/test_sigma_ingest.py +212 -0
- zettelforge-2.4.0/tests/test_sigma_parser.py +125 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_two_phase_e2e.py +18 -15
- zettelforge-2.4.0/tests/test_yara_entities.py +170 -0
- zettelforge-2.4.0/tests/test_yara_ingest.py +126 -0
- zettelforge-2.4.0/tests/test_yara_parser.py +126 -0
- zettelforge-2.4.0/web/mcp_server.py +18 -0
- zettelforge-2.2.0/ARCHITECTURE.md +0 -36
- zettelforge-2.2.0/docs/assets/logo.svg +0 -3
- zettelforge-2.2.0/docs/assets/social-preview.png +0 -0
- zettelforge-2.2.0/docs/assets/threatrecall-logo.svg +0 -22
- zettelforge-2.2.0/docs/assets/threatrecall-mark.svg +0 -12
- zettelforge-2.2.0/docs/llms.txt +0 -50
- zettelforge-2.2.0/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -113
- zettelforge-2.2.0/docs/stylesheets/extra.css +0 -10
- zettelforge-2.2.0/src/zettelforge/llm_client.py +0 -150
- zettelforge-2.2.0/tests/test_causal_extraction.py +0 -91
- zettelforge-2.2.0/tests/test_llm_client.py +0 -76
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/CODEOWNERS +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/SECURITY.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/dependabot.yml +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/pull_request_template.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/workflows/publish.yml +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/.github/workflows/snyk-security.yml +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/CODEOWNERS +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/CONTRIBUTING.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/Dockerfile +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/GOVERNANCE.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/LICENSE +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/MANIFEST.in +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/auto_ralph.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/benchmark_harness.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/cti_benchmark_v2.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/cti_retrieval_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/cti_retrieval_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/cti_v2_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/ctibench_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/ctibench_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/dataset.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/enterprise-attack.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/evolve_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/evolve_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/graph_test.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/locomo_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/locomo_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/memoryagentbench.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/memoryagentbench_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/mempalace_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/mempalace_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/naive_memory.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/opencti_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/ragas_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/ragas_cti_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/ragas_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/results/benchmark_report.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/results/ralph_optimization_log.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/scale_benchmark.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/benchmarks/scale_results.json +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/config.example.yaml +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docker/docker-compose.yml +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/CNAME +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0/docs/archive}/PACKAGE_SUMMARY.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0/docs/archive}/SKILL.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/assets/demo.gif +0 -0
- /zettelforge-2.2.0/docs/assets/favicon.svg → /zettelforge-2.4.0/docs/assets/favicon-old.svg +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/assets/threatrecall-logo-philosophy.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/assets/threatrecall-logo.png +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/assets/threatrecall-mark.png +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/explanation/epistemic-tiers.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/explanation/two-phase-pipeline.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/explanation/zettelkasten-philosophy.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/configure-lancedb.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/configure-opencti.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/configure-typedb.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/ingest-news-report.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/query-apt-tools.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/resolve-aliases.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/run-temporal-query.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/how-to/store-threat-actor.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/reference/retrieval-policies.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/docs/reference/stix-schema.md +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-09-ctibench-ragas-benchmarks.md +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-09-fastembed-local-embeddings.md +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-09-hybrid-typedb-lancedb-architecture.md +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-09-local-llm-llama-cpp.md +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-15-anti-aversion-cleanup.md +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-15-ctibench-ate-fix.md +0 -0
- {zettelforge-2.2.0/docs/superpowers/plans → zettelforge-2.4.0/docs/superpowers/research}/2026-04-15-sqlite-migration.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/examples/athf_bridge.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/examples/mcp_claude_code.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/examples/quickstart.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/governance/controls.yaml +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/scripts/migrate_jsonl_to_sqlite.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/scripts/rebuild_index.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/scripts/record-demo.sh +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/scripts/typedb-setup.sh +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/scripts/zettelforge-rebuild.service +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/scripts/zettelforge-rebuild.timer +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/skills/claude-code-skill.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/skills/openclaw-skill.md +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/__main__.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/alias_resolver.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/blended_retriever.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/consolidation.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/demo.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/edition.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/extensions.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/fact_extractor.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/governance_validator.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/graph_retriever.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/integrations/__init__.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/intent_classifier.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/json_parse.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/knowledge_graph.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/log.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/memory_evolver.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/memory_store.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/memory_updater.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/note_constructor.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/note_schema.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/retry.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/storage_backend.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/synthesis_generator.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/synthesis_validator.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/src/zettelforge/vector_memory.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/__init__.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/benchmark_scale.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/conftest.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_basic.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_blended_retriever.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_config.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_consolidation.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_cti_integration.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_edition.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_embedding.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_extensions.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_fact_extractor.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_governance.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_governance_spec_drift.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_graph_retriever.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_intent_classifier.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_json_parse.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_logging_compliance.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_memory_evolver.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_memory_updater.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_performance.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_recall_integration.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_sqlite_backend.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_sqlite_integration.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_storage_backend.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_temporal_graph.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/tests/test_typedb_client.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/web/app.py +0 -0
- {zettelforge-2.2.0 → zettelforge-2.4.0}/web/auth.py +0 -0
|
@@ -14,8 +14,8 @@ jobs:
|
|
|
14
14
|
deploy:
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
18
|
-
- uses: actions/setup-python@
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
- uses: actions/setup-python@v6
|
|
19
19
|
with:
|
|
20
20
|
python-version: '3.12'
|
|
21
21
|
- run: pip install mkdocs-material
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
config.yaml
|
|
3
3
|
config.yml
|
|
4
4
|
.env
|
|
5
|
+
.env.*
|
|
6
|
+
*.key
|
|
7
|
+
*.pem
|
|
5
8
|
|
|
6
9
|
# Local planning & task tracking (not committed)
|
|
7
10
|
TODO.md
|
|
@@ -62,7 +65,7 @@ htmlcov/
|
|
|
62
65
|
vectordb/
|
|
63
66
|
.vector_memory.lance/
|
|
64
67
|
.snapshots/
|
|
65
|
-
archive/
|
|
68
|
+
/archive/
|
|
66
69
|
|
|
67
70
|
# Data directories (runtime, not source)
|
|
68
71
|
/data/
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Visual diagram: [`docs/architecture-diagram.mmd`](docs/architecture-diagram.mmd)
|
|
4
|
+
Deep explanation: [`docs/explanation/architecture.md`](docs/explanation/architecture.md)
|
|
5
|
+
|
|
6
|
+
## Storage
|
|
7
|
+
|
|
8
|
+
ZettelForge uses a `StorageBackend` ABC (33 methods) with pluggable
|
|
9
|
+
implementations. Set `ZETTELFORGE_BACKEND` to select.
|
|
10
|
+
|
|
11
|
+
- **SQLite** (default since v2.2.0): WAL mode, ACID, zero-config.
|
|
12
|
+
Notes, knowledge graph, and entity index in one database file.
|
|
13
|
+
- **LanceDB**: Vector index alongside SQLite. 768-dim embeddings
|
|
14
|
+
via fastembed (nomic-embed-text-v1.5-Q, ONNX, in-process).
|
|
15
|
+
|
|
16
|
+
## Core Pipeline
|
|
17
|
+
|
|
18
|
+
1. **Ingestion** — Governance validation → Note construction → Entity
|
|
19
|
+
extraction (regex fast-path + LLM) → Alias resolution → Storage
|
|
20
|
+
2. **Enrichment** (background) — Causal triple extraction, memory
|
|
21
|
+
evolution (A-Mem neighbor refinement), HGAM consolidation
|
|
22
|
+
3. **Retrieval** — Intent classification → Blended vector + graph
|
|
23
|
+
search → Temporal/causal boosting → Cross-encoder reranking
|
|
24
|
+
4. **Synthesis** — RAG-as-Answer with quality validation
|
|
25
|
+
|
|
26
|
+
## Extension Points
|
|
27
|
+
|
|
28
|
+
Extensions are optional packages discovered at startup via
|
|
29
|
+
`src/zettelforge/extensions.py`. If installed, they provide
|
|
30
|
+
alternative backends and integrations.
|
|
31
|
+
|
|
32
|
+
- Knowledge graph: TypeDB STIX 2.1 ontology with inference rules
|
|
33
|
+
- Authentication: Multi-tenant OAuth/JWT
|
|
34
|
+
- Integrations: OpenCTI bi-directional sync, Sigma rule generation
|
|
35
|
+
|
|
36
|
+
## Why These Boundaries
|
|
37
|
+
|
|
38
|
+
TypeDB requires a running server. OpenCTI is a complex platform.
|
|
39
|
+
These dependencies should not be required to try ZettelForge.
|
|
40
|
+
|
|
41
|
+
The default backends are not toy implementations — they are
|
|
42
|
+
production-capable for single-user and small-team deployments.
|
|
@@ -6,6 +6,204 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.4.0] - 2026-04-19
|
|
10
|
+
|
|
11
|
+
Detection-rules-as-memory, MCP Registry publication, SQLite concurrency
|
|
12
|
+
hardening, and a full test-suite hygiene pass.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Detection rules as first-class memory** (#70) — Sigma and YARA rules
|
|
17
|
+
are now ingested, indexed, and retrieved alongside CTI entities, with
|
|
18
|
+
an LLM rule explainer that surfaces what each rule detects and the
|
|
19
|
+
actors/techniques it's associated with. See the "Detection Rules as
|
|
20
|
+
Memory" section in the README (#74) for usage.
|
|
21
|
+
- **MCP Registry publication** (#75) — `server.json` and the `mcp-name`
|
|
22
|
+
tag required to publish ZettelForge to the canonical MCP Registry
|
|
23
|
+
(registry.modelcontextprotocol.io), which feeds mcp.so and the
|
|
24
|
+
modelcontextprotocol.io community-servers list.
|
|
25
|
+
- **Brand & docs polish** (#61) — neural-chain architecture diagram with
|
|
26
|
+
light/dark parity, updated GitHub social preview, canonical security
|
|
27
|
+
channels + RFC 9116 `security.txt`, real Code of Conduct contacts,
|
|
28
|
+
and a complete brand documentation set.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **SQLite backend concurrency** (#69) — 16 reader methods in
|
|
33
|
+
`SQLiteBackend` (`get_note_by_id`, `get_note_by_source_ref`,
|
|
34
|
+
`iterate_notes`, `get_notes_by_domain`, `get_recent_notes`,
|
|
35
|
+
`count_notes`, `get_kg_node`, `get_kg_node_by_id`,
|
|
36
|
+
`get_kg_neighbors`, `traverse_kg`, `get_entity_timeline`,
|
|
37
|
+
`get_changes_since`, `get_causal_edges`, `get_incoming_causal`,
|
|
38
|
+
`get_note_ids_for_entity`, `search_entities`) were executing
|
|
39
|
+
`SELECT` statements without holding `_write_lock`, while writers
|
|
40
|
+
acquired it. Under concurrent background enrichment, readers could
|
|
41
|
+
observe a partially-written row and raise `pydantic.ValidationError`
|
|
42
|
+
on NULL columns. Each reader now wraps its SQL execute+fetch block
|
|
43
|
+
in `with self._write_lock:` (RLock, reentrant-safe). Closes #68.
|
|
44
|
+
Eliminates the `test_apply_delete_marks_superseded` flake and
|
|
45
|
+
prevents the same race from surfacing in production
|
|
46
|
+
`recall()`-during-write paths.
|
|
47
|
+
- **CI regressions** (#67) — stabilized three tests exposed by the
|
|
48
|
+
test-suite audit sprint.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- **Test suite hygiene** (#62, #63, #64, #65) — post-v2.3.0 audit (see
|
|
53
|
+
`docs/superpowers/research/2026-04-17-test-suite-audit.md`)
|
|
54
|
+
converted 10 CI-skipped LLM tests to the mock provider (RFC-002
|
|
55
|
+
Phase 1), resolved both remaining `xfail` tests via prompt-routed
|
|
56
|
+
mocks, eliminated two long-standing flakes
|
|
57
|
+
(`test_recall_cve_returns_notes`, `test_apply_delete_marks_superseded`),
|
|
58
|
+
prepped `langchain_retriever` for Pydantic V3 by migrating to
|
|
59
|
+
`ConfigDict`, and reinstated meaningful causal-edge validation via
|
|
60
|
+
mock-seeded triples + `SQLiteBackend.get_causal_edges` query. Net
|
|
61
|
+
test-suite delta: 280 passed / 17 skipped / 2 xfailed → 305 passed
|
|
62
|
+
/ 10 skipped / 0 xfailed on test-3.12.
|
|
63
|
+
|
|
64
|
+
## [2.3.0] - 2026-04-17
|
|
65
|
+
|
|
66
|
+
Pluggable LLM provider infrastructure (RFC-002 Phase 1), MCP server
|
|
67
|
+
as a first-class Python module, PyPI discoverability refresh, SEO
|
|
68
|
+
foundations across the docs site, and a full docs-vs-code
|
|
69
|
+
reconciliation. All additions are backward-compatible; no existing
|
|
70
|
+
API changes. Supersedes the never-tagged 2.2.1 metadata patch —
|
|
71
|
+
its PyPI classifier / keyword / image-URL changes are folded in
|
|
72
|
+
below.
|
|
73
|
+
|
|
74
|
+
### Added
|
|
75
|
+
|
|
76
|
+
- **Pluggable LLM provider infrastructure (RFC-002 Phase 1)** — new
|
|
77
|
+
`zettelforge.llm_providers` package with a `@runtime_checkable`
|
|
78
|
+
`LLMProvider` protocol, a thread-safe registry, and built-in
|
|
79
|
+
providers for `local` (llama-cpp-python), `ollama`, and `mock`.
|
|
80
|
+
The public `generate()` signature is unchanged; all 7 existing call
|
|
81
|
+
sites (`fact_extractor`, `memory_updater`, `synthesis_generator`,
|
|
82
|
+
`intent_classifier`, `note_constructor`, `entity_indexer`,
|
|
83
|
+
`memory_evolver`) keep working without modification. Third-party
|
|
84
|
+
providers can register via the `zettelforge.llm_providers`
|
|
85
|
+
entry-point group. `openai_compat` and `anthropic` providers land
|
|
86
|
+
in Phase 2 and Phase 3.
|
|
87
|
+
- **`LLMConfig` expanded** — new `api_key`, `timeout`, `max_retries`,
|
|
88
|
+
`fallback`, and `extra` fields. `api_key` supports `${ENV_VAR}`
|
|
89
|
+
references and is redacted from `repr()`. Sensitive keys inside
|
|
90
|
+
`extra` (matching `key|token|secret|password|credential|auth`) are
|
|
91
|
+
redacted as well. New env overrides: `ZETTELFORGE_LLM_API_KEY`,
|
|
92
|
+
`ZETTELFORGE_LLM_TIMEOUT`, `ZETTELFORGE_LLM_MAX_RETRIES`,
|
|
93
|
+
`ZETTELFORGE_LLM_FALLBACK`.
|
|
94
|
+
- **`LLMProviderConfigurationError`** — new exception surfaced for
|
|
95
|
+
non-recoverable provider setup problems (bad API key, missing
|
|
96
|
+
optional SDK) so `generate()` can distinguish "try the fallback"
|
|
97
|
+
from "stop and report".
|
|
98
|
+
- **`llm_client.reload()` helper** — clears the provider registry
|
|
99
|
+
and config cache so test suites and long-lived processes can
|
|
100
|
+
reconfigure the LLM backend without a process restart.
|
|
101
|
+
- **Hardened .gitignore** per GOV-023 — added `.env.*`, `*.key`,
|
|
102
|
+
`*.pem`.
|
|
103
|
+
- **MCP server as a first-class module** — `python -m zettelforge.mcp`
|
|
104
|
+
now works out of a `pip install zettelforge` with no git clone
|
|
105
|
+
required. New package `zettelforge.mcp` (with `server.py`,
|
|
106
|
+
`__main__.py`, and a console-script entry `zettelforge-mcp`).
|
|
107
|
+
The previous entry point at `web/mcp_server.py` is retained as a
|
|
108
|
+
thin backward-compat shim.
|
|
109
|
+
- **Console scripts** — `zettelforge` and `zettelforge-mcp` entry
|
|
110
|
+
points added to `pyproject.toml`.
|
|
111
|
+
- **How-to guides** — migration (`migrate-jsonl-to-sqlite.md`),
|
|
112
|
+
benchmark reproduction (`reproduce-benchmarks.md`), troubleshooting
|
|
113
|
+
(`troubleshoot.md`), and upgrade (`upgrade.md`). Linked from the
|
|
114
|
+
MkDocs nav.
|
|
115
|
+
- **Design and About sections in the docs nav** — RFC-001, RFC-002,
|
|
116
|
+
RFC-003 and the origin-story narrative are now discoverable from
|
|
117
|
+
`docs.threatrecall.ai`.
|
|
118
|
+
- **RFC-003 design proposal (docs only)** — read-path depth routing
|
|
119
|
+
with a deterministic Quality Gate plus System 1 / System 2 recall
|
|
120
|
+
paths. Ships with an adversarial-review artifact (4 blockers, 13
|
|
121
|
+
warnings). No runtime changes yet — implementation deferred.
|
|
122
|
+
- **Archive directory** — `docs/archive/` holds retired v1.0.0-alpha
|
|
123
|
+
snapshots (`SKILL.md`, `PACKAGE_SUMMARY.md`) with a README explaining
|
|
124
|
+
their provenance.
|
|
125
|
+
- **`llm_ner` configuration reference** — `docs/reference/configuration.md`
|
|
126
|
+
now documents `llm_ner.enabled` and the `ZETTELFORGE_LLM_NER_ENABLED`
|
|
127
|
+
environment override.
|
|
128
|
+
- **Docs SEO foundation** — per-page canonical URLs, OpenGraph and
|
|
129
|
+
Twitter-card metadata, and a `SoftwareApplication` JSON-LD block on
|
|
130
|
+
the home page via a `docs/overrides/main.html` theme override. The
|
|
131
|
+
`softwareVersion` value is sourced from `config.extra.version` in
|
|
132
|
+
`mkdocs.yml` so it stays in sync with releases.
|
|
133
|
+
- **PyPI classifier refresh** — added `Topic :: Security` (primary
|
|
134
|
+
filter security engineers use to browse PyPI) and
|
|
135
|
+
`Topic :: Software Development :: Libraries :: Python Modules`.
|
|
136
|
+
Existing `Topic :: Scientific/Engineering :: Artificial Intelligence`
|
|
137
|
+
retained. Development Status stays at `4 - Beta`.
|
|
138
|
+
- **PyPI keyword refresh** — swapped `agent-memory` → `agentic-memory`
|
|
139
|
+
(emerging category keyword) and `zettelkasten` → `llm-memory`
|
|
140
|
+
(direct intent match for Mem0/Graphiti discovery traffic). Still
|
|
141
|
+
10 keywords total; within the PyPI display limit.
|
|
142
|
+
|
|
143
|
+
### Changed
|
|
144
|
+
|
|
145
|
+
- **SECURITY.md** — contact updated to `contact@threatrecall.ai`,
|
|
146
|
+
supported-versions table refreshed to mark `2.3.x` as current and
|
|
147
|
+
`2.2.x` as the prior minor release; storage section refreshed to
|
|
148
|
+
reflect SQLite-by-default.
|
|
149
|
+
- **`docs/llms.txt`** — rewritten to match current reality (SQLite
|
|
150
|
+
default, 19 runtime entity types, correct GOV-003/007/011/012
|
|
151
|
+
descriptions, MCP invocation).
|
|
152
|
+
- **BENCHMARK_REPORT.md** — CTIBench ATE row updated (F1 = 0.146);
|
|
153
|
+
architecture summary reframed as SQLite + LanceDB default with
|
|
154
|
+
TypeDB as an extension; `ctibench_results.json` date bumped.
|
|
155
|
+
- **README** — above-fold rewritten (CTA row, keyword density,
|
|
156
|
+
PyPI-safe absolute-URL images). Pipeline step 1 entity count
|
|
157
|
+
corrected from "10 types" to the 19 types `EntityExtractor`
|
|
158
|
+
actually recognises.
|
|
159
|
+
- **README image paths** — `docs/assets/demo.gif` and
|
|
160
|
+
`docs/assets/zettelforge_architecture.svg` rewritten to absolute
|
|
161
|
+
`raw.githubusercontent.com` URLs so the PyPI long description
|
|
162
|
+
renders correctly (relative paths 404 on the PyPI CDN). Pinned to
|
|
163
|
+
the `master` ref; can be re-pinned to the `v2.3.0` tag in the
|
|
164
|
+
next release PR if PyPI-side stability matters.
|
|
165
|
+
- **`docs/superpowers/plans/` renamed to `docs/superpowers/research/`**
|
|
166
|
+
with a README making clear these are aspirational synthesis, not
|
|
167
|
+
roadmap commitments. The stray untracked `docs/plans/` directory
|
|
168
|
+
was removed.
|
|
169
|
+
- **Tutorials and governance-controls reference** — `last_updated`
|
|
170
|
+
and `version` metadata refreshed.
|
|
171
|
+
- **`zettelforge.ontology` exports** — `TypedEntityStore`,
|
|
172
|
+
`OntologyValidator`, `get_ontology_store`, `get_ontology_validator`
|
|
173
|
+
removed from the top-level `__all__` (still importable from
|
|
174
|
+
`zettelforge.ontology`). They are a parallel store not wired into
|
|
175
|
+
`MemoryManager`.
|
|
176
|
+
- **`observability.py` and `cache.py` headers** — annotated as
|
|
177
|
+
currently unwired; kept for future integration.
|
|
178
|
+
- **OCSF `_PRODUCT_VERSION`** — sourced from
|
|
179
|
+
`importlib.metadata.version("zettelforge")` instead of a hard-coded
|
|
180
|
+
string, so emitted OCSF events stop drifting when `__version__`
|
|
181
|
+
bumps.
|
|
182
|
+
- **OpenGraph `og:type`** — `website` on the home page, `article`
|
|
183
|
+
elsewhere (was unconditionally `article`).
|
|
184
|
+
|
|
185
|
+
### Fixed
|
|
186
|
+
|
|
187
|
+
- **OllamaProvider host routing** — now instantiates
|
|
188
|
+
`ollama.Client(host=self._url)` so the configured URL actually
|
|
189
|
+
takes effect (previously the module-level `ollama.generate()` call
|
|
190
|
+
ignored per-instance host).
|
|
191
|
+
- **Provider registry race** — `register()` now checks and mutates
|
|
192
|
+
under the registry lock, closing a TOCTOU window on concurrent
|
|
193
|
+
provider registration.
|
|
194
|
+
- **MCP server lazy instantiation** — `MemoryManager` is now created
|
|
195
|
+
on first tool call rather than at server import time, so `--help`
|
|
196
|
+
and protocol-handshake tests don't pay the model-load cost.
|
|
197
|
+
|
|
198
|
+
### Removed
|
|
199
|
+
|
|
200
|
+
- Six superseded branches that had already been squash-merged into
|
|
201
|
+
master — `feat/causal-chain-fix-and-demo-gif`,
|
|
202
|
+
`feat/entity-vocabulary-expansion`,
|
|
203
|
+
`feature/RFC-001-conversational-entity-extractor`,
|
|
204
|
+
`fix/intent-classifier-graph-weight`,
|
|
205
|
+
`fix/p0-production-blockers`, `feat/remember-evolve`.
|
|
206
|
+
|
|
9
207
|
## [2.2.0] - 2026-04-16
|
|
10
208
|
|
|
11
209
|
SQLite default backend, causal chain retrieval, memory evolution, STIX taxonomy alignment, and community-first package cleanup.
|
|
@@ -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 [
|
|
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
|
|
|
@@ -1,30 +1,37 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zettelforge
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: ZettelForge: Agentic Memory System with vector search, knowledge graph, and synthesis
|
|
5
5
|
Project-URL: Homepage, https://github.com/rolandpg/zettelforge
|
|
6
|
-
Project-URL: Documentation, https://
|
|
6
|
+
Project-URL: Documentation, https://docs.threatrecall.ai
|
|
7
7
|
Project-URL: Repository, https://github.com/rolandpg/zettelforge
|
|
8
8
|
Project-URL: Issues, https://github.com/rolandpg/zettelforge/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/rolandpg/zettelforge/blob/master/CHANGELOG.md
|
|
9
10
|
Author-email: Patrick Roland <patrick@groland.com>
|
|
10
11
|
License-Expression: MIT
|
|
11
12
|
License-File: LICENSE
|
|
12
|
-
Keywords:
|
|
13
|
-
Classifier: Development Status ::
|
|
13
|
+
Keywords: agentic-memory,ai-agent,cti,cybersecurity,knowledge-graph,llm-memory,mcp-server,rag,stix,threat-intelligence
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
15
|
Classifier: Intended Audience :: Developers
|
|
15
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
17
|
Classifier: Programming Language :: Python :: 3
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
22
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Security
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
25
|
Requires-Python: >=3.10
|
|
22
26
|
Requires-Dist: fastembed>=0.8.0
|
|
23
27
|
Requires-Dist: httpx>=0.25.0
|
|
28
|
+
Requires-Dist: jsonschema>=4.0
|
|
24
29
|
Requires-Dist: lancedb>=0.5.0
|
|
25
30
|
Requires-Dist: numpy>=1.24.0
|
|
31
|
+
Requires-Dist: plyara>=2.0
|
|
26
32
|
Requires-Dist: pyarrow>=14.0.0
|
|
27
33
|
Requires-Dist: pydantic>=2.0.0
|
|
34
|
+
Requires-Dist: pyyaml>=6.0
|
|
28
35
|
Requires-Dist: requests>=2.31.0
|
|
29
36
|
Requires-Dist: structlog>=24.0.0
|
|
30
37
|
Requires-Dist: tantivy>=0.11.0
|
|
@@ -48,23 +55,28 @@ Description-Content-Type: text/markdown
|
|
|
48
55
|
|
|
49
56
|
# ZettelForge
|
|
50
57
|
|
|
58
|
+
<!-- mcp-name: io.github.rolandpg/zettelforge -->
|
|
59
|
+
|
|
51
60
|
**The only agentic memory system built for cyber threat intelligence.**
|
|
52
61
|
|
|
53
|
-
|
|
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.
|
|
54
63
|
|
|
55
64
|
[](https://pypi.org/project/zettelforge/)
|
|
56
|
-
[](https://pepy.tech/projects/zettelforge)
|
|
57
|
-
[](https://github.com/rolandpg/zettelforge/stargazers)
|
|
58
|
-
[](https://opensource.org/licenses/MIT)
|
|
65
|
+
[](https://pepy.tech/projects/zettelforge)
|
|
59
66
|
[](https://www.python.org/downloads/)
|
|
67
|
+
[](https://opensource.org/licenses/MIT)
|
|
60
68
|
[](https://github.com/rolandpg/zettelforge/actions)
|
|
61
|
-
|
|
62
|
-
[
|
|
63
|
-
[](https://safeskill.dev/scan/rolandpg-zettelforge)
|
|
69
|
+
|
|
70
|
+
**[⭐ Star](https://github.com/rolandpg/zettelforge) · [📦 `pip install zettelforge`](https://pypi.org/project/zettelforge/) · [📖 Docs](https://docs.threatrecall.ai/) · [🧪 Hosted](https://threatrecall.ai)**
|
|
64
71
|
|
|
65
72
|
<p align="center">
|
|
66
|
-
|
|
73
|
+
<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>
|
|
67
74
|
</p>
|
|
75
|
+
<p align="center">
|
|
76
|
+
<img src="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/demo.gif" width="720" alt="ZettelForge demo — CTI agentic memory in action">
|
|
77
|
+
</p>
|
|
78
|
+
|
|
79
|
+
> If ZettelForge fits a CTI workflow you run, a star is the fastest signal that this category is worth continuing to invest in.
|
|
68
80
|
|
|
69
81
|
## Why ZettelForge?
|
|
70
82
|
|
|
@@ -72,6 +84,9 @@ General-purpose memory systems don't understand threat intelligence. They can't
|
|
|
72
84
|
|
|
73
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.
|
|
74
86
|
|
|
87
|
+
>"Memory augmentation closes 33% of the gap between small and large models on CTI tasks (CTI-REALM, Microsoft 2026)." [1]
|
|
88
|
+
|
|
89
|
+
|
|
75
90
|
| Feature | ZettelForge | Mem0 | Graphiti | Cognee |
|
|
76
91
|
|---------|------------|------|----------|--------|
|
|
77
92
|
| CTI entity extraction (CVEs, actors, IOCs) | Yes | No | No | No |
|
|
@@ -83,6 +98,16 @@ ZettelForge was built from the ground up for analysts who think in threat graphs
|
|
|
83
98
|
| OCSF audit logging | Yes | No | No | No |
|
|
84
99
|
| MCP server (Claude Code) | Yes | No | No | No |
|
|
85
100
|
|
|
101
|
+
## Data Pipeline
|
|
102
|
+
<p align="center">
|
|
103
|
+
<picture>
|
|
104
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture.svg">
|
|
105
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rolandpg/zettelforge/master/docs/assets/zettelforge_architecture-light.svg">
|
|
106
|
+
<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">
|
|
107
|
+
</picture>
|
|
108
|
+
</p>
|
|
109
|
+
|
|
110
|
+
|
|
86
111
|
## Features
|
|
87
112
|
|
|
88
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.
|
|
@@ -148,7 +173,7 @@ mm.remember(
|
|
|
148
173
|
|
|
149
174
|
Every `remember()` call triggers a pipeline:
|
|
150
175
|
|
|
151
|
-
1. **Entity Extraction** -- regex + LLM NER identifies CVEs, actors, tools, campaigns, people, locations,
|
|
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)
|
|
152
177
|
2. **Knowledge Graph Update** -- entities become nodes, co-occurrence becomes edges, LLM infers causal triples
|
|
153
178
|
3. **Vector Embedding** -- 768-dim fastembed (ONNX, in-process, 7ms/embed) stored in LanceDB
|
|
154
179
|
4. **Supersession Check** -- entity overlap detection marks stale notes as superseded
|
|
@@ -192,6 +217,35 @@ Your Claude Code agent can now remember and recall threat intelligence across se
|
|
|
192
217
|
|
|
193
218
|
Exposed tools: `remember`, `recall`, `synthesize`, `entity`, `graph`, `stats`.
|
|
194
219
|
|
|
220
|
+
## Detection Rules as Memory (Sigma + YARA)
|
|
221
|
+
|
|
222
|
+
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
|
+
|
|
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`.
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
from zettelforge import MemoryManager
|
|
228
|
+
from zettelforge.sigma import ingest_rule as ingest_sigma
|
|
229
|
+
from zettelforge.yara import ingest_rule as ingest_yara
|
|
230
|
+
|
|
231
|
+
mm = MemoryManager()
|
|
232
|
+
ingest_sigma("rules/proc_creation_win_office_macro.yml", mm)
|
|
233
|
+
ingest_yara("rules/webshell_china_chopper.yar", mm, tier="warn")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Bulk ingest from SigmaHQ or a private rule repo
|
|
238
|
+
python -m zettelforge.sigma.ingest /path/to/sigma/rules/
|
|
239
|
+
python -m zettelforge.yara.ingest /path/to/yara/rules/ --tier warn
|
|
240
|
+
|
|
241
|
+
# CI fixture check -- parse + validate, no writes
|
|
242
|
+
python -m zettelforge.sigma.ingest rules/ --dry-run
|
|
243
|
+
```
|
|
244
|
+
|
|
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).
|
|
246
|
+
|
|
247
|
+
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
|
+
|
|
195
249
|
## Integrations
|
|
196
250
|
|
|
197
251
|
### ATHF (Agentic Threat Hunting Framework)
|
|
@@ -206,26 +260,6 @@ python examples/athf_bridge.py /path/to/hunts/
|
|
|
206
260
|
|
|
207
261
|
See [examples/athf_bridge.py](examples/athf_bridge.py).
|
|
208
262
|
|
|
209
|
-
## Architecture
|
|
210
|
-
|
|
211
|
-
```
|
|
212
|
-
┌──────────────────────────────────────────────────────────────────────┐
|
|
213
|
-
│ MemoryManager │
|
|
214
|
-
│ remember() remember_with_extraction() recall() synthesize() │
|
|
215
|
-
├──────────┬───────────┬──────────────┬───────────┬────────────────────┤
|
|
216
|
-
│ Note │ Fact │ Memory │ Blended │ Synthesis │
|
|
217
|
-
│Constructor│ Extractor │ Updater │ Retriever │ Generator │
|
|
218
|
-
│(enrich) │(Phase 1) │(Phase 2) │(vec+graph)│ (RAG) │
|
|
219
|
-
├──────────┴───────────┴──────────────┼───────────┴────────────────────┤
|
|
220
|
-
│ Entity Indexer + Alias │ Intent Classifier │
|
|
221
|
-
│ Resolver │ (factual/temporal/causal) │
|
|
222
|
-
├─────────────────────────────────────┼────────────────────────────────┤
|
|
223
|
-
│ Knowledge Graph (SQLite) │ LanceDB (Vectors) │
|
|
224
|
-
│ Entity nodes + edges │ 768-dim fastembed (ONNX) │
|
|
225
|
-
│ Causal triple inference │ Zettelkasten notes │
|
|
226
|
-
│ SQLite WAL (TypeDB via extension) │ IVF_PQ index │
|
|
227
|
-
└─────────────────────────────────────┴────────────────────────────────┘
|
|
228
|
-
```
|
|
229
263
|
|
|
230
264
|
## Extensions
|
|
231
265
|
|
|
@@ -272,6 +306,12 @@ MIT -- See [LICENSE](LICENSE).
|
|
|
272
306
|
|
|
273
307
|
**Made by Patrick Roland**.
|
|
274
308
|
|
|
309
|
+
## Support the Project
|
|
310
|
+
|
|
311
|
+
ZettelForge is MIT-licensed. If it's useful in your workflow and you'd like to help keep it maintained:
|
|
312
|
+
|
|
313
|
+
<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>
|
|
314
|
+
|
|
275
315
|
## Acknowledgments
|
|
276
316
|
|
|
277
317
|
- Inspired by [Zettelkasten](https://en.wikipedia.org/wiki/Zettelkasten) and [A-Mem](https://arxiv.org/abs/2602.10715) (NeurIPS 2025)
|
|
@@ -279,3 +319,5 @@ MIT -- See [LICENSE](LICENSE).
|
|
|
279
319
|
- STIX 2.1 schema informed by [typedb-cti](https://github.com/typedb-osi/typedb-cti)
|
|
280
320
|
- Benchmarked against [LOCOMO](https://snap-research.github.io/locomo/) (ACL 2024) and [CTIBench](https://arxiv.org/abs/2406.07599) (NeurIPS 2024)
|
|
281
321
|
- [LanceDB](https://lancedb.com) | [fastembed](https://github.com/qdrant/fastembed) | [Pydantic](https://pydantic.dev) | [TypeDB](https://typedb.com)
|
|
322
|
+
|
|
323
|
+
[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/
|