Try-it-out instructions for running Mulder, the forensic investigation platform.
- Usage Guide
- Docker or Podman installed and running. All commands below use
docker, butpodmanworks as a drop-in replacement. - Evidence to analyze. A directory containing disk images, memory dumps, event logs, or other forensic artifacts.
- An LLM provider account. One of the following:
- An Anthropic API key
- A Google Cloud project with Vertex AI enabled and Claude model access
- An AWS account with Amazon Bedrock Claude model access
- Any LiteLLM-supported provider (OpenAI, Ollama, Azure, etc.)
- Disk space for case output. Investigations produce databases, audit logs, and reports that are written to a host-mounted directory.
The pre-built container image includes all forensic tools, dependencies, and the Mulder server:
docker pull ghcr.io/calebevans/mulder:1.3Every docker run invocation requires two volume mounts:
| Mount Path | Purpose |
|---|---|
/evidence |
Your evidence directory (mount read-only with :ro) |
/home/mulder/.mulder/cases |
Case databases, audit logs, and reports (persisted to host) |
Create the cases directory on the host before your first run:
mkdir -p ~/mulder-casesThe --privileged flag is required for FUSE operations that several forensic tools depend on (ewfmount for E01 images, guestmount for VM disk images, etc.).
If --privileged is too permissive for your environment, use the narrower capability grant instead:
--cap-add SYS_ADMIN --device /dev/fuseThe container runs as a non-root mulder user. An entrypoint script handles credential copying and permission setup automatically.
The simplest configuration passes your API key as an environment variable:
docker run -it --privileged \
-v /path/to/evidence:/evidence:ro \
-v ~/mulder-cases:/home/mulder/.mulder/cases \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ghcr.io/calebevans/mulder:1.3To route requests through Vertex AI, mount your GCP credentials file into the container and set the Vertex environment variables:
docker run -it --privileged \
-v /path/to/evidence:/evidence:ro \
-v ~/mulder-cases:/home/mulder/.mulder/cases \
-e CLAUDE_CODE_USE_VERTEX=1 \
-e CLOUD_ML_REGION=us-east5 \
-e ANTHROPIC_VERTEX_PROJECT_ID=your-gcp-project-id \
-e GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcloud-creds.json \
-v ~/.config/gcloud/application_default_credentials.json:/tmp/gcloud-creds.json:ro \
ghcr.io/calebevans/mulder:1.3Model IDs are passed through to the SDK exactly as specified, with no automatic translation or mapping. When using Vertex, you must provide the full Vertex model ID including the @version suffix (e.g. --model claude-opus-4-6@20250514). If you omit --model, the built-in defaults (claude-opus-4-6 for planner/analyst, claude-haiku-4-5 for executor) are used.
| Variable | Description |
|---|---|
CLAUDE_CODE_USE_VERTEX |
Set to 1 to enable Vertex AI |
CLOUD_ML_REGION |
GCP region where Claude is enabled (e.g. us-east5) |
ANTHROPIC_VERTEX_PROJECT_ID |
Your GCP project ID |
GOOGLE_APPLICATION_CREDENTIALS |
Path inside the container to the mounted credentials file |
If you use Application Default Credentials (ADC) from gcloud auth application-default login, the default host path is ~/.config/gcloud/application_default_credentials.json.
Pass your AWS credentials and region as environment variables:
docker run -it --privileged \
-v /path/to/evidence:/evidence:ro \
-v ~/mulder-cases:/home/mulder/.mulder/cases \
-e CLAUDE_CODE_USE_BEDROCK=1 \
-e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
ghcr.io/calebevans/mulder:1.3Model IDs are passed through to the SDK exactly as specified, with no automatic translation or mapping. When using Bedrock, you must provide the full Bedrock model ID with the us.anthropic. prefix (e.g. --model us.anthropic.claude-opus-4-6). If you omit --model, the built-in defaults (claude-opus-4-6 for planner/analyst, claude-haiku-4-5 for executor) are used.
| Variable | Description |
|---|---|
CLAUDE_CODE_USE_BEDROCK |
Set to 1 to enable Bedrock |
AWS_REGION |
AWS region with Bedrock Claude model access |
AWS_ACCESS_KEY_ID |
AWS access key |
AWS_SECRET_ACCESS_KEY |
AWS secret key |
You can also mount ~/.aws/credentials if you prefer file credentials over environment variables.
Once the container is running, launch a full autonomous investigation with mulder investigate. The command takes two positional arguments: the evidence path and a case ID:
mulder investigate /evidence my-caseThe case ID names the output database and all derived artifacts. Choose something descriptive (e.g. the incident ticket number or a short codename).
The orchestrator runs five phases in sequence:
- Catalog scans the evidence directory, classifies file types, and identifies distinct systems.
- Extraction runs forensic tools per system (memory analysis, disk forensics, log parsing) and submits findings.
- Cross-System Analysis correlates evidence across systems and maps findings to MITRE ATT&CK techniques.
- Alternative Narrative challenges the primary hypothesis, searches for counter-evidence, and audits for completeness.
- Report generates the investigation narrative and final report artifacts.
Each phase passes through a quality gate before proceeding. The investigation runs unattended from start to finish.
Mulder includes a built-in LiteLLM proxy that enables any LiteLLM-supported model provider. No manual proxy setup is required.
When any model ID includes a provider prefix, the proxy starts automatically:
# Bedrock Llama
mulder investigate /evidence my-case \
--model bedrock/meta.llama3-1-70b-instruct-v1:0
# OpenAI
mulder investigate /evidence my-case \
--model openai/gpt-4oSupported prefixes: bedrock/, openai/, vertex_ai/, azure/, ollama/.
Mulder uses three agent roles (planner, executor, analyst), and each can use a different model. This lets you route expensive reasoning to a stronger model while using a cheaper one for mechanical tool execution:
mulder investigate /evidence my-case \
--executor-model bedrock/meta.llama3-1-70b-instruct-v1:0 \
--planner-model claude-opus-4-6 \
--analyst-model claude-opus-4-6To use a locally hosted model via Ollama, ensure the Ollama server is accessible from inside the container (e.g. via host networking) and pass the ollama/ prefix:
mulder investigate /evidence my-case \
--model ollama/llama3.1:70bFor advanced model routing, load balancing, or custom deployments, pass a LiteLLM configuration file:
mulder investigate /evidence my-case \
--proxy-config ./litellm_config.yaml \
--model my-custom-deploymentSee the LiteLLM documentation for config file format details.
You can provide investigation context by placing a MULDER.md file in the root of your evidence directory. This is optional but recommended when you have background knowledge about the case.
- What We Know: Facts established before the investigation (incident reports, help desk tickets, network topology, known-compromised accounts)
- What We're Looking For: Specific questions the investigation should answer (who, what, when, how)
- Supplementary Context: Class rosters, org charts, IP ranges, account naming conventions, or anything that helps interpret evidence
- Constraints: Timezone information, scope limitations, legal holds
The contents of MULDER.md are prepended as an "INVESTIGATOR BRIEFING" to the planner and analyst prompts in every phase. This means:
- The extraction planner uses it to prioritize which tools to run
- The analyst uses it to focus analysis on relevant questions
- The cross-system correlator uses it to understand relationships
- The report writer uses it to frame conclusions around your questions
# Case Briefing
## Background
Employee John Doe (username: jdoe) reported suspicious activity on his
workstation on 2024-03-15. IT observed outbound connections to unknown
IPs. The workstation and a file server were imaged.
## Known Facts
- Affected systems: WKSTN-042 (10.1.2.42), FILE-SRV (10.1.2.10)
- Suspect timeframe: March 14-15, 2024
- jdoe has local admin on WKSTN-042
## Investigation Questions
1. How did the attacker gain access to jdoe's workstation?
2. Did the attacker move laterally to FILE-SRV?
3. Was any data staged or exfiltrated?
4. Are there persistence mechanisms that survive a reboot?If no MULDER.md is present, the investigation proceeds without additional context (fully autonomous mode).
The extraction planner adapts its tool selection based on what the evidence actually contains, not just its type. Standard toolsets (Volatility for memory, Sleuthkit for disk) always run, but the planner also looks for signals that indicate targeted analysis is warranted.
Windows disk images automatically trigger registry queries for system metadata (timezone, install date, shutdown time) and NTUSER.DAT parsing for user activity artifacts (TypedURLs, RecentDocs, UserAssist, MRU lists).
Execution artifacts (ShimCache, Prefetch, Amcache, UserAssist) are inspected for communication and networking tools. When the planner detects IRC clients, email clients, chat applications, or remote access tools in execution history, it plans index_app_files tasks targeting their configuration and data directories. When packet capture tools like Wireshark appear, the planner adds analyze_disk_pcaps to discover saved captures on disk.
Investigator briefing keywords also influence tool selection. Briefings mentioning hacking or intrusion trigger searches for exploit tool configs and PCAPs. Briefings about insider threats or data theft prioritize USB history and cloud storage artifacts. Briefings about communications prioritize email and chat application data.
The analyst receives complementary guidance: when execution artifacts show communication tools were used, the analyst searches indexed application files for contacts, server addresses, and credentials, then cross-references those with network connection data.
mulder investigate <evidence_path> <case_id> [OPTIONS]
Runs a full multi-phase forensic investigation.
| Option | Default | Description |
|---|---|---|
--model |
None | Fallback model for all roles |
--planner-model |
claude-opus-4-6 |
Model for planner agents |
--executor-model |
claude-haiku-4-5 |
Model for executor agents |
--analyst-model |
claude-opus-4-6 |
Model for analyst agents |
--config |
None | YAML config file for models and settings |
--effort |
max |
Effort level (max, xhigh, high) |
--workers |
3 |
Max concurrent extraction sessions |
--db-dir |
~/.mulder/cases |
Case database directory |
--cwd |
/mulder-investigation |
Working directory for agent sessions |
--proxy-config |
None | LiteLLM config YAML for custom model routing |
mulder serve [OPTIONS]
Starts the MCP server standalone. Normally invoked automatically by the orchestrator.
| Option | Default | Description |
|---|---|---|
--case-id |
None | Pre-load an existing case on startup |
--db-dir |
~/.mulder/cases |
Directory for case databases and audit logs |
--transport |
stdio |
MCP transport (stdio or streamable-http) |
--workers |
8 |
Concurrent tool execution threads |
--mem-limit |
90 |
Memory usage % threshold (0 to disable) |
--cpu-limit |
90 |
CPU usage % threshold (0 to disable) |
mulder report <case_id> [OPTIONS]
Regenerates reports (Markdown, HTML, PDF) offline from an existing case database.
| Option | Default | Description |
|---|---|---|
--db-dir |
~/.mulder/cases |
Directory containing case databases |
mulder export-iocs <case_id> [OPTIONS]
Exports IOCs from a completed case.
| Option | Default | Description |
|---|---|---|
--db-dir |
~/.mulder/cases |
Directory containing case databases |
--format |
stix |
Output format (stix or csv) |
mulder export-navigator <case_id> [OPTIONS]
Generates a MITRE ATT&CK Navigator layer from a completed case.
| Option | Default | Description |
|---|---|---|
--db-dir |
~/.mulder/cases |
Directory containing case databases |
After an investigation completes, all artifacts are written to the cases directory you mounted at /home/mulder/.mulder/cases (e.g. ~/mulder-cases on the host).
| File | Description |
|---|---|
{case_id}.db |
SQLite database with all indexed evidence, findings, and metadata |
{case_id}.audit.jsonl |
Append-only audit log recording every tool invocation with parameters and timestamps |
| File | Description |
|---|---|
{case_id}.report.md |
Markdown report for plain-text review |
{case_id}.report.html |
Self-contained HTML report with dark/light theme and sidebar navigation |
{case_id}.report.pdf |
PDF report for formal distribution |
All report formats include an executive summary, severity overview, evidence integrity hashes, attack timeline, detailed findings with MITRE ATT&CK mappings, IOC tables, audit metrics, and a sources appendix.
| File | Description |
|---|---|
{case_id}.stix.json |
STIX 2.1 IOC bundle |
{case_id}.iocs.csv |
CSV IOC export |
{case_id}.navigator.json |
MITRE ATT&CK Navigator layer (load in the Navigator web app) |
| File | Description |
|---|---|
mulder.log |
MCP server log |
orchestrator.log |
Orchestrator log with phase progress and gate results |
To customize tools, add new MCP tools, or work from the latest development branch, build the container image locally:
git clone https://github.com/calebevans/mulder.git
cd mulder
docker build -t mulder:dev .Then run with the same volume mounts, substituting mulder:dev for the registry image:
docker run -it --privileged \
-v /path/to/evidence:/evidence:ro \
-v ~/mulder-cases:/home/mulder/.mulder/cases \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
mulder:devA Makefile is included for convenience. Run make help to see available targets.