GNAT Architecture Decision Records
A single reference for every design decision made during development, including tradeoffs, alternatives considered, and implementation notes. Use this when testing, implementing new connectors, or extending existing subsystems.
Table of Contents
- ADR-0001: HTTP Client Layer
- ADR-0002: ORM / STIX Compatibility
- ADR-0003: Connector Architecture
- ADR-0004: Ingestion Framework
- ADR-0005: Context System — Global and Local
- ADR-0006: Workspace Persistence
- ADR-0007: Async Client
- ADR-0008: Visualization — Tabular
- ADR-0009: Visualization — Graph
- ADR-0010: Visualization — Grafana vs Power BI
- ADR-0011: CLI Design
- ADR-0012: Code Generation
- ADR-0013: Configuration
- ADR-0014: Testing Strategy
- ADR-0015: Packaging and Extras
- ADR-0016: Feed Scheduling
- ADR-0017: Export / Integration Pipeline
- ADR-0018: AI Agent Layer
- ADR-0019: Shared Research Library
- ADR-0020: NLP Query Layer
- ADR-0021: Rust Native Extension (
gnat-core) - ADR-0022: Web Dashboard (
gnat/serve/) - ADR-0023: Terminal UI — Textual
- ADR-0024: XSOAR Content Pack Generator
- ADR-0025: Upstream Contribution Pipeline
- ADR-0026: Connector Health Monitor
- ADR-0027: Multi-Tenant Workspace Isolation
- ADR-0028: TAXII 2.1 Server
- ADR-0029: Docker Containerization
- ADR-0030: Use Diátaxis and ADRs
- ADR-0031: Analysis Layer Architecture
- ADR-0032: STIX Custom Objects
- ADR-0033: Confidence Scoring
- ADR-0034: Report Lifecycle
- ADR-0035: Quality Agents
- ADR-0036: Security Agents Phase B
- ADR-0037: Adopt Responsible Disclosure, DCO, and Apache 2.0 Compliance
- ADR-0038: Data Lineage Tracking
Phase 4 — Control, Reasoning, Safety
- ADR-0039: Unified Execution Context
- ADR-0040: Connector Trust Model
- ADR-0041: Idempotency and Schema Evolution
- ADR-0042: Hypothesis Engine
- ADR-0043: Negative Evidence Tracking
- ADR-0044: Reasoning Engine
- ADR-0045: Agent Governance
- ADR-0046: HITL Gateway
- ADR-0047: Workspace Isolation and Trust Boundaries
- ADR-0048: Query Budget and Cost Model
- ADR-0049: Testing Framework — Simulation and Replay
Detection, Attribution & Telemetry
- ADR-0050: HuntGNAT — Detection Rule Translation
- ADR-0051: Attribution & Campaign Tracking
- ADR-0052: Telemetry Ingestion
- ADR-0053: Infrastructure Graph Labels
- ADR-0054: Analysis Rule Engine
Cross-Tool Integration
GUI Foundation
Quick Reference: Adding a New Connector
# 1. Generate scaffold
gnat-codegen --spec platform-openapi.json --name myplatform --auth oauth2
# 2. Implement in gnat/connectors/myplatform/client.py
# - authenticate()
# - to_stix(native) → dict with type, id, created, modified
# - from_stix(stix_dict) → platform-native payload
# - health_check()
# - get_object(), list_objects(), upsert_object(), delete_object()
# 3. Register sync connector
# gnat/clients/__init__.py:
CLIENT_REGISTRY["myplatform"] = MyplatformClient
# 4. Add async mirror
# gnat/async_client/connectors.py: add AsyncMyplatformClient
# gnat/async_client/client.py: add to _build_async_registry()
# 5. Add INI section to config/config.ini.example
# 6. Add [global.myplatform] block to ADR-0013 (0013-ADR-configuration.md)
# 7. Run tests
pytest tests/unit/connectors/ -v
Quick Reference: Adding a New Ingest Source
# SourceReader subclass
class MyReader(SourceReader):
def _iter_records(self) -> Iterator[RawRecord]:
# yield plain dicts
# RecordMapper subclass
class MyMapper(RecordMapper):
def map(self, record: RawRecord) -> Iterator[STIXBase]:
# yield STIXBase objects using self._client, self.tlp_marking, self.confidence
# Register in:
# gnat/ingest/sources/__init__.py
# gnat/ingest/mappers/__init__.py
# gnat/__init__.py (both __all__ and import)
Quick Reference: Workspace Investigation Workflow
from gnat import GNATClient
from gnat.context import WorkspaceManager, GlobalContextRegistry
# Setup (once per session)
tq = GNATClient().connect("threatq")
rf = GNATClient().connect("recordedfuture") # read-only
cs = GNATClient().connect("crowdstrike")
manager = WorkspaceManager.from_clients(
{"threatq": tq, "rf": rf, "crowdstrike": cs},
default="threatq",
read_only=["rf"],
)
# Investigation
ws = manager.get_or_create("campaign-name")
ws.load("indicator", filters={"tags": "apt28"})
ws.enrich(
sources=["rf", "crowdstrike"],
strategy="create_relationships", # preserves provenance
confidence_floor=60,
)
print(ws.diff()) # what changed
result = ws.commit() # write back to ThreatQ
print(result)
# Visualize
from gnat.viz import TabularView, GraphView
TabularView(ws).show()
GraphView(ws).to_html("graph.html") # auto-selects sigma.js at scale
Licensed under the Apache License, Version 2.0