Shared principles
- The portable MarlinSpike report artifact remains the primary handoff between packet analysis and downstream review.
- Optional extensions must run headlessly and must not require Flask, a browser, or a database connection.
- Machine-readable outputs should be deterministic and versioned.
- Packet-facing code should not make site-policy decisions.
- Report-facing code should not parse raw packet captures directly.
- YAML must stay declarative.
Rust engine contract
Rust engines own packet-facing and event-heavy work: reading captures, parsing protocols, normalizing transactions, and emitting structured observations or artifacts.
They do not own final topology scoring, responder-facing finding text, ATT&CK mapping, site-specific policy, or UI behavior.
marlinspike-dpi --input <pcap> --capture-id <id> --output <json> --pretty The minimum invocation contract is simple: accept an input capture path, accept a stable capture identifier, write JSON output to a caller-specified path, and return non-zero on failure.
Python plugin contract
Python plugins consume a finished MarlinSpike report JSON and emit a sidecar artifact for enrichment, correlation, ATT&CK mapping, IEC 62443 mapping, malware matching, or other post-processing.
python -m marlinspike_plugin_name \
--input-report <report.json> \
--output <artifact.json> The plugin should not mutate the input report in place. The sidecar artifact is authoritative, while a merged report can exist as a convenience copy.
{
"artifact_type": "plugin_output",
"plugin_id": "marlinspike-plugin-name",
"plugin_version": "0.1.0",
"contract_version": 1,
"summary": {},
"data": {},
"warnings": []
} YAML rule pack contract
YAML rule packs are the declarative layer. They are meant for mappings, local overrides, enable and disable controls, and policy content that analysts may need to tune without rewriting code during an engagement.
The docs are explicit about what YAML should not become: a general programming language, a hidden parser surface, or a place to bury arbitrary logic that belongs in a plugin.
Rule of thumb for new work
- If it consumes raw
pcap, packet streams, or high-volume protocol events, it probably belongs in a Rust engine. - If it consumes the finished MarlinSpike report artifact, it probably belongs in a Python plugin.
- If analysts should be able to tune it without code changes, it probably belongs in a YAML rule pack.