Skip to content

STIX-aligned extraction and graph reference

ZettelForge turns common CTI indicators and names into lowercase entity labels, then connects co-occurring entities in its local knowledge graph. Use this reference when you call an entity-recall method, inspect note metadata, or write a relationship directly.

Prerequisites

  • ZettelForge 2.8.0.
  • A MemoryManager instance when you use the recall or relationship methods.
  • A working LLM provider only when you need the conversational enrichment labels marked in progress below.

Scope and naming

This page covers the ZettelForge open-source extraction index, note metadata, and the SQLite knowledge-graph path used by MemoryManager. It does not describe the hosted ThreatRecall.ai graph schema.

ZettelForge 2.8.0 has two related vocabularies. Keep their spelling separate:

  • The extraction index and MemoryManager use lowercase labels such as intrusion_set and uppercase graph relationships such as USES_TOOL.
  • The typed ontology validator uses PascalCase entities such as IntrusionSet and lowercase relationships such as uses_tool. It is a separate validation surface; do not pass its PascalCase names to the recall methods on this page.

Extraction-index entity labels

remember() runs the deterministic regex extractor before it writes entity mappings. Regex matches are lowercased, and spaces become hyphens. Match order is not stable because the extractor deduplicates with sets.

CTI labels

Label Example output Deterministic match
cve cve-2024-3094 CVE- + four digits + at least four digits
intrusion_set apt28, unc4990, ta505, fin7 APT, UNC, TA, FIN, or TEMP designation plus digits
actor lazarus, sandworm, volt-typhoon One of the three built-in actor names
tool cobalt-strike, metasploit, mimikatz, bloodhound, dropbear, empire, covenant One of the seven built-in tool names
campaign operation-aurora operation followed by one word
attack_pattern t1059, t1059.001 ATT&CK technique or sub-technique identifier

Observable labels

Label Match
ipv4 IPv4 address with each octet constrained to 0–255
domain Domain name with one of the suffixes registered in the extractor
url Text beginning with http:// or https:// up to a delimiter
md5 32 hexadecimal characters
sha1 40 hexadecimal characters
sha256 64 hexadecimal characters
email Address-shaped text with a dotted suffix

The hash extractor rejects candidates that appear in assignment, Git commit, or fenced-code contexts. The URL regex does not strip terminal periods or commas; surround a URL with a delimiter or normalize the captured value before you use it as an IOC.

Conversational labels

Label Deterministic path LLM enrichment path
person A name of 3–16 letters at the start of a Name: dialogue line, minus the built-in stop list Broader person names
location One of 43 built-in city or place names Broader locations
organization None Named organizations
event None Named events
activity None Described activities
temporal None Time expressions

Conversational LLM enrichment is in progress

No Ollama service was listening on 127.0.0.1:11434 during this run, so the LLM enrichment path was not verified. When generation fails, the extractor catches the error and returns empty lists for all six conversational labels. The deterministic person and location matches above were executed.

Entity recall methods

Method ZettelForge 2.8.0 signature Lookup behavior
recall_entity (entity_type: str, entity_value: str, k: int = 5) -> list[MemoryNote] Looks up one lowercase extraction-index label. It lowercases the value.
recall_actor (actor_name: str, k: int = 5) -> list[MemoryNote] Searches actor, threat_actor, then intrusion_set, and removes duplicate notes.
recall_technique (technique_id: str, k: int = 25) -> list[MemoryNote] Searches attack_pattern; the wrapper uppercases the input before the shared lookup lowercases it.

recall_entity() does not validate entity_type. An unknown label returns no mapped notes unless a caller has written mappings under that label.

Note metadata fields

Every MemoryNote has a metadata object. These are the STIX-adjacent fields and related confidence fields in ZettelForge 2.8.0.

Field Type Default Meaning
stix_confidence int -1 STIX confidence from 0–100; -1 means unset. The model does not enforce the range.
tier str "B" Epistemic tier. A is authoritative, B operational, and C support. The model does not restrict other strings.
tlp str "" Stored TLP text. ZettelForge 2.8.0 does not normalize or validate this field in Metadata.
confidence float 1.0 Internal confidence. increment_evolution() caps it at 0.95.
vuln VulnerabilityMeta | None None Structured vulnerability data attached by an import or sync path.

VulnerabilityMeta

Field Type Default
cvss_v3_score float | None None
cvss_v3_vector str | None None
epss_score float | None None
epss_percentile float | None None
cisa_kev bool False

The model describes the numeric ranges in comments but does not enforce bounds at construction time.

Built-in SQLite graph relationships

remember() creates a note node, MENTIONED_IN edges, and heuristic edges for co-occurring entities. Heuristic edges store first_observed and the note's internal confidence as properties.

Relationship From To Writer
MENTIONED_IN Any extracted entity note remember()
USES_TOOL actor, threat_actor, intrusion_set tool remember()
EXPLOITS_CVE Actor label or tool cve remember()
TARGETS_ASSET Actor label or tool asset remember() when another path supplies asset entities
CONDUCTS_CAMPAIGN Actor label campaign remember()
USES_TECHNIQUE Actor label attack_pattern remember()
IMPLEMENTS malware attack_pattern remember() when another path supplies malware entities
AFFILIATED_WITH person organization LLM entity enrichment
ATTENDED person event LLM entity enrichment
LOCATED_AT person location LLM entity enrichment
PARTICIPATES_IN person activity LLM entity enrichment
HELD_AT event location LLM entity enrichment
ORGANIZED_BY event organization LLM entity enrichment
OCCURRED_ON event temporal LLM entity enrichment
BASED_IN organization location LLM entity enrichment
SUPERSEDES New note Old note mark_note_superseded()

The regex extractor does not emit asset or malware. Their rows activate only when an import, sync, or enrichment path supplies those entity lists. The eight conversational relationships remain in progress because this run did not exercise LLM enrichment.

ingest_relationship()

The method accepts source and target labels, a relationship string, and optional properties. It returns None. The method does not validate the labels against the typed ontology.

mm.ingest_relationship(
    from_type="actor",
    from_value="apt28",
    to_type="tool",
    to_value="mimikatz",
    relationship="USES_TOOL",
    properties={"confidence": 0.9},
)

The SQLite edge key is the source node, target node, and relationship. Repeating the call updates the existing edge properties instead of adding another edge. The method also writes the same edge to the legacy JSONL knowledge graph for backward compatibility.

Typed CTI ontology vocabulary

The separate OntologyValidator exposes these core CTI names in 2.8.0:

  • Entity types: IntrusionSet, ThreatActor, Vulnerability, Malware, Campaign, Incident, and AttackPattern.
  • Relationship types: attributed_to, uses, uses_technique, uses_tool, exploits, implements, and targets.

Use this PascalCase/snake_case vocabulary only with the ontology validation surface. Use the lowercase/uppercase vocabulary in the earlier tables with MemoryManager.