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