Complete guide to every command, flag, and workflow. For a 60-second overview see the README; for deployment see deployment.md.
- Install
- Mental model
- The commands
- End-to-end walkthrough
- Working without a dump
- Web API
- Acquiring memory (Talon & friends)
- Troubleshooting
python -m venv .venv && . .venv/bin/activate
pip install -e ".[vol]" # + Volatility3 (needed only for `run`)
pip install -e ".[web]" # + FastAPI/uvicorn (needed only for `serve`)
pip install -e ".[yara]" # + yara-python (needed only for YARA scans)
pip install -e ".[vol,web,dev]" # everything + test depsVerify:
mneme --version
mneme --helpVolatility3, FastAPI and YARA are all optional. Without them the analysis
pipeline (parse/detect/timeline/report/export/stix) still runs on
pre-collected Volatility3 JSON.
A case is a directory. Mneme fills it in stages and never mixes raw evidence with derived data:
case/
├── raw/ # verbatim Volatility3 JSON, one file per plugin
│ ├── windows.pslist.json
│ ├── windows.malfind.json
│ └── …
├── ecs/ # normalized ECS v8 events, one file per dataset
│ ├── windows.pslist.ecs.jsonl
│ └── …
└── report.html # rendered on demand
Data flows one way:
dump.raw ──run──▶ case/raw ──parse──▶ case/ecs ──▶ detect
│
├──▶ timeline
├──▶ report
├──▶ export (jsonl/csv)
└──▶ stix
Only run touches the dump and needs Volatility3. Everything downstream reads
case/ecs, so you can hand a colleague just the ECS files and they get the same
detections.
Global: mneme [COMMAND] --help prints per-command help.
Execute Volatility3 plugins against a memory dump into case/raw/.
mneme run DUMP -o CASE_DIR [options]| Flag | Default | Meaning |
|---|---|---|
-o, --output |
(required) | Case dir; raw/ created inside |
--os {windows,linux,mac} |
inferred | Force OS profile (default: guess from dump filename) |
--plugin NAME |
— | Run only these plugins (repeatable); skips the recommended set |
--vol-bin PATH |
vol |
Volatility3 binary to invoke |
--workers N |
4 |
Concurrency for parallel-safe plugins |
Behavior:
- Auto-detects OS, then runs the recommended plugin set for it
(
mneme plugins --os windowsto preview). - Parallel-safe plugins (pslist, netscan, malfind, …) run concurrently; ordering plugins run first.
- Results are cached by
sha256(dump) + plugin + args— re-running is instant and safe. - One failing plugin never aborts the triage; failures are reported and skipped.
# full recommended triage, auto OS
mneme run memory.raw -o case/
# force Linux, 8 workers
mneme run vmcore -o case/ --os linux --workers 8
# just two plugins
mneme run mem.raw -o case/ --plugin windows.malfind --plugin windows.netscan
# custom Vol3 binary
mneme run mem.raw -o case/ --vol-bin /opt/vol3/volNormalize raw Vol3 JSON → ECS v8 events in case/ecs/.
mneme parse RAW_DIR -o CASE_DIRReads every *.json in RAW_DIR, infers the dataset from the filename stem
(cache digests like windows.pslist.ab12cd34.json are stripped), dispatches to
the matching parser, and writes <dataset>.ecs.jsonl. Files with no parser or
bad JSON are skipped with a warning.
Run malware-detection heuristics over normalized events.
mneme detect ECS_INPUT [--yara RULES] [--json]| Flag | Meaning |
|---|---|
--yara PATH |
YARA rules file (source or compiled); scans malfind regions |
--json |
Emit raw JSON instead of a table |
ECS_INPUT is a case/ecs directory (all *.ecs.jsonl loaded) or a single
file. Findings are ranked by severity then confidence; findings sharing a PID
reinforce each other's confidence (correlation bump).
Detections (each MITRE ATT&CK-mapped):
| Type | Technique | ATT&CK |
|---|---|---|
| process_injection | RWX private memory | T1055 |
| process_hollowing | anomalous parent | T1055.012 |
| dkom | hidden process (scan ∖ list) | T1014 |
| rootkit | hooked syscall/SSDT/IDT | T1014 |
| persistence | service → LOLBin / temp path | T1543.003 |
| credential_theft | lsass injection / access | T1003.001 |
| yara_match | rule hit on malfind | — |
mneme detect case/ecs
mneme detect case/ecs --yara rules/malware.yar
mneme detect case/ecs --json | jq '.[] | select(.severity=="critical")'Build an ordered timeline; optionally cluster bursts.
mneme timeline ECS_INPUT [--cluster] [--json] [--limit N]| Flag | Default | Meaning |
|---|---|---|
--cluster |
off | Group events into 1-second windows |
--json |
off | Raw JSON output |
--limit N |
50 |
Rows to show in table mode |
mneme timeline case/ecs --limit 100
mneme timeline case/ecs --cluster
mneme timeline case/ecs --json > timeline.jsonRender a self-contained HTML report (summary cards, ranked findings, IOCs, timeline). No external assets — open offline or embed in a wiki.
mneme report CASE_DIR [--os OS] [-o OUTPUT]| Flag | Default | Meaning |
|---|---|---|
--os |
windows |
OS label shown in the header |
-o, --output |
CASE_DIR/report.html |
Report path |
mneme report case/
mneme report case/ --os linux -o /srv/reports/case42.htmlConvert normalized events to JSONL or CSV, optionally gzipped.
mneme export ECS_INPUT -o OUTPUT [--format {jsonl,csv}] [--gzip]mneme export case/ecs -o events.jsonl
mneme export case/ecs -o events.csv --format csv
mneme export case/ecs -o events.jsonl.gz --gzipExtract IOCs (routable IPs, domains, file paths) and emit a STIX 2.1 bundle.
mneme stix ECS_INPUT [-o OUTPUT] # stdout if -o omittedmneme stix case/ecs -o iocs.stix.json
mneme stix case/ecs | jq '.objects | length'List the recommended plugin set for an OS.
mneme plugins --os {windows,linux,mac}List datasets that have a registered parser.
mneme parsersLaunch the web GUI + JSON API (needs [web]).
mneme serve [--host 0.0.0.0] [--port 8080]# 0. env
python -m venv .venv && . .venv/bin/activate && pip install -e ".[vol]"
# 1. acquire (see Talon section) → memory.raw
# 2. run Volatility3 triage
mneme run memory.raw -o case/
# 3. normalize
mneme parse case/raw -o case/
# 4. triage findings
mneme detect case/ecs
mneme timeline case/ecs --cluster
# 5. deliverables
mneme report case/ # → case/report.html
mneme stix case/ecs -o iocs.json
mneme export case/ecs -o events.csv --format csvNo Volatility3? No dump on this host? Produce Vol3 JSON anywhere and analyze it
with Mneme. File names must be <plugin>.json:
# on the box that has Vol3 + the dump
for p in windows.pslist windows.pstree windows.malfind windows.netscan \
windows.cmdline windows.svcscan; do
vol -r json -f mem.raw "$p" > "case/raw/$p.json"
done
# anywhere (offline, no Vol3)
mneme parse case/raw -o case/
mneme detect case/ecs
mneme report case/This is exactly how the test suite runs — see tests/fixtures/.
Start with mneme serve (or Docker). Dashboard at /, API under /api.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/cases |
List cases |
| POST | /api/cases/{name}/raw?dataset=X |
Upload a raw Vol3 JSON file (auto-parsed) |
| GET | /api/cases/{name}/detections |
Findings JSON |
| GET | /api/cases/{name}/timeline?cluster=true |
Timeline JSON |
| GET | /api/cases/{name}/iocs |
Extracted IOCs |
| GET | /api/cases/{name}/report?os_type=windows |
HTML report |
| GET | /healthz |
Liveness |
curl -F file=@case/raw/windows.pslist.json \
"http://localhost:8080/api/cases/demo/raw?dataset=windows.pslist"
curl http://localhost:8080/api/cases/demo/detections | jq .Cases persist under MNEME_DATA (default /data). Case names are validated
to a single path segment (no traversal).
Mneme analyzes memory; it does not acquire it. Talon — the Citadel
suite's acquisition agent (first node of the pipeline) — does the acquisition.
Talon writes an artifact bundle; its memory category produces exactly the
raw image Mneme consumes. They chain directly:
Talon ──bundle(memory/*.dmp)──▶ Mneme run ──▶ parse ──▶ detect/report
Memory is a Heavy / Opt-in category — never in Talon's defaults (dumps are 4–64 GB), so request it explicitly. Per-OS engine:
| OS | Engine | Bundle path | Format |
|---|---|---|---|
| Windows | WinPmem (winpmem_mini_x64_rc2.exe beside the collector) |
memory/memory-<HOST>-<TS>.dmp |
raw |
| Linux | avml (fallback /dev/fmem), root |
memory/memory-<HOST>-<TS>.lime / .raw |
LiME / raw |
| macOS | osxpmem, root | memory/memory-<HOST>-<TS>… |
AFF4 |
Volatility3 reads all three natively, so every one feeds mneme run
unchanged. Talon also has a memory_artifacts category (dead-box pagefile.sys,
hiberfil.sys, swapfile.sys from a mounted volume).
# 1. ACQUIRE on the target (elevated). WinPmem must sit beside the collector.
talon --collect memory --output E:\evidence\host01.zip
# → bundle: manifest.json | events.jsonl | memory/memory-host01-<ts>.dmp | bundle.sha256
# 2. EXTRACT the memory image on the analysis workstation
unzip E:\evidence\host01.zip -d host01_bundle
# the dump is the file under memory/ (category "memory" in manifest.json)
DUMP=$(python3 - <<'PY'
import json,glob
m=json.load(open(glob.glob("host01_bundle/**/manifest.json",recursive=True)[0]))
print(next(a["name"] for a in m["artifacts"] if a["category"]=="memory"))
PY
)
# 3. ANALYZE with Mneme
mneme run "host01_bundle/$DUMP" -o case_host01/
mneme parse case_host01/raw -o case_host01/
mneme detect case_host01/ecs
mneme report case_host01/- Formats line up. Talon's WinPmem
.dmp, avml.lime, and osxpmem AFF4 are all Volatility3-native — no conversion. - Integrity carries through. Talon's
manifest.jsonrecords each artifact'ssha256; Mneme keys its own result cache onsha256(dump). Compare the two to prove the analyzed image is the acquired one. - Same case, both stages. Both tools speak the Citadel suite: Talon uploads
bundles to a case (
--api-url … --case-id IR-001); Mneme emits ECS + STIX, ready to push to the same case. - Air-gapped split. Acquire with Talon on the target, run
vol -r jsonon a clean host,mneme parseoffline — no dump ever leaves the enclave (see Working without a dump).
Talon's gRPC agent (mTLS) collects memory across a fleet and lands bundles in
S3/MinIO. Pull a bundle, extract its memory/ file, and point mneme run
at it — identical from step 2 onward.
- WinPmem is not bundled with Talon — drop
winpmem_mini_x64_rc2.exebeside the collector (Talon prints a download URL if it's missing). - Acquisition needs elevation (Administrator / root) and can take up to 2 h; Talon's per-dump timeout is 2 h.
hiberfil.sysfrommemory_artifactsis compressed — decompress (e.g.hibr2bin) beforemneme run; a live.dmp/.lime/AFF4 needs no such step.
| Symptom | Cause / fix |
|---|---|
'vol' not found on run |
Volatility3 missing → pip install -e ".[vol]" or pass --vol-bin |
no parser for 'X' on parse |
That plugin has no mapper yet; other files still parse. See mneme parsers |
web extras missing on serve |
pip install -e ".[web]" |
| YARA findings never appear | pip install -e ".[yara]" and pass --yara rules.yar |
| Empty detections | Confirm case/ecs/*.ecs.jsonl exist and are non-empty (parse ran) |
run seems to hang |
Large dumps are slow; each plugin has a 30-min timeout. Watch per-plugin progress lines |
| Externally-managed-environment pip error | Use a venv (python -m venv .venv) |