STIX schema reference¶
ZettelForge recognizes STIX-aligned entity types during extraction, stores STIX metadata fields on every note, and maintains a knowledge graph of relationships between entities. This page describes all three.
TypeDB STIX 2.1 ontology
The full STIX 2.1 TypeDB ontology — including TypeQL entity hierarchies, relation types, and inference functions — is available in ThreatRecall.ai, the hosted SaaS. The OSS package stores entity references in SQLite and an in-memory graph; the data structures on this page cover that path.
Entity types¶
ZettelForge extracts entities from text when you call remember(). Two extraction
paths run in sequence:
- Regex fast-path — deterministic, no LLM required. Covers CTI and IOC types.
- LLM NER — conversational types. Requires a configured LLM provider.
CTI entity types (regex)¶
| Entity type | Example match | Pattern |
|---|---|---|
cve |
CVE-2024-1234 |
CVE-\d{4}-\d{4,} |
intrusion_set |
APT28, UNC4990, TA505, FIN7 |
(apt\|unc\|ta\|fin\|temp)\s*-?\s*\d+ |
actor |
Lazarus, Sandworm, Volt Typhoon |
hardcoded known names |
tool |
Cobalt Strike, Mimikatz, BloodHound |
hardcoded known names |
campaign |
Operation Aurora |
operation\s+\w+ |
attack_pattern |
T1059, T1059.001 |
T\d{4}(?:\.\d{3})? |
IOC entity types / STIX Cyber Observables (regex)¶
| Entity type | Description |
|---|---|
ipv4 |
IPv4 address |
domain |
Registered domain name |
url |
HTTP/HTTPS URL |
md5 |
32-character hex hash |
sha1 |
40-character hex hash |
sha256 |
64-character hex hash |
email |
Email address |
Conversational entity types (LLM NER)¶
Requires a configured LLM provider. Falls back to empty lists when no provider is available.
| Entity type | Description |
|---|---|
person |
Named person (non-threat-actor context) |
location |
Place name |
organization |
Named organization |
event |
Named event |
activity |
Described activity |
temporal |
Time expression |
Entity type aliases in recall methods¶
recall_actor() searches across three entity types in one call: actor,
threat_actor, and intrusion_set. All three map to the same lookup
path.
recall_entity() accepts any entity type string directly. Pass "cve", "tool",
"campaign", or any other recognized type.
Note metadata: STIX fields¶
Every MemoryNote carries these STIX-adjacent fields on its metadata object.
stix_confidence¶
Type: int
Default: -1 (unset)
Range: 0 to 100
Standard: STIX 2.1 confidence scale
Set automatically during OpenCTI sync when the source platform provides a
confidence value. -1 means no STIX confidence has been assigned.
tier¶
Type: str
Default: "B"
Values: "A" | "B" | "C"
Epistemic tier:
| Tier | Meaning |
|---|---|
A |
Authoritative — from a primary, verified source |
B |
Operational — derived, processed, or synthesized |
C |
Support — background, context, or low-confidence |
tlp¶
Type: str
Default: "" (unclassified)
Values: "WHITE" | "GREEN" | "AMBER" | "RED" | ""
Traffic Light Protocol marking. Notes with AMBER or RED markings are
excluded from snapshot exports unless an audited TLP override is provided.
confidence¶
Type: float
Default: 1.0
Range: 0.0 to 1.0
Internal confidence score. Decays when a note is evolved: each evolution
caps confidence at 0.95. Distinct from stix_confidence.
vuln (VulnerabilityMeta)¶
Structured CVE scoring fields. Populated during OpenCTI sync, not during text extraction.
| Field | Type | Description |
|---|---|---|
cvss_v3_score |
float \| None |
CVSS v3 base score (0.0–10.0) |
cvss_v3_vector |
str \| None |
CVSS v3 vector string, e.g. CVSS:3.1/AV:N/AC:L/... |
epss_score |
float \| None |
EPSS exploitation probability (0.0–1.0, daily) |
epss_percentile |
float \| None |
EPSS percentile relative to all scored CVEs (0.0–1.0) |
cisa_kev |
bool |
True if the CVE is in the CISA Known Exploited Vulnerabilities catalog |
vuln is None for non-CVE notes. For CVE notes before any OpenCTI sync, it
is also None.
Knowledge graph relationship types¶
When you call remember(), ZettelForge heuristically creates edges in the
knowledge graph when STIX-relevant entities co-occur in the same note. You can
also write edges directly with ingest_relationship().
Edge types¶
| Relationship | From entity type | To entity type | Created by |
|---|---|---|---|
MENTIONED_IN |
any | note |
remember() |
USES_TOOL |
actor, campaign |
tool |
remember() (heuristic) |
EXPLOITS_CVE |
actor, tool |
cve |
remember() (heuristic) |
TARGETS_ASSET |
actor, tool |
asset |
remember() (heuristic) |
CONDUCTS_CAMPAIGN |
actor |
campaign |
remember() (heuristic) |
SUPERSEDES |
note |
note |
mark_note_superseded() |
TEMPORAL_BEFORE |
note |
note |
temporal ordering |
TEMPORAL_AFTER |
note |
note |
temporal ordering |
Heuristic edges are created when two entity types appear in the same note.
They carry edge_type: "heuristic". Causal edges written via
ingest_relationship() or provenance chains carry edge_type: "causal".
ingest_relationship()¶
Write a relationship edge directly into the knowledge graph without creating a memory note. Useful for sync clients that carry relationship data from external platforms.
mm.ingest_relationship(
from_type="actor",
from_value="apt28",
to_type="tool",
to_value="mimikatz",
relationship="USES_TOOL",
properties={"confidence": 0.9},
)
The call is idempotent: repeated writes with the same
(from_type, from_value, to_type, to_value, relationship) tuple update the
edge properties rather than creating duplicates.