Reference

CLI reference

The macfor binary exposes a small surface: discover plugins, collect artifacts, and inspect manifests. Every command supports --help.

Top-level usage

macfor [global flags] <command> [command flags]

Commands:
  list         List available plugins and categories
  collect      Collect artifacts into an evidence container
  manifest     Inspect or validate plugin manifests
  completion   Generate a shell completion script
  help         Show contextual help

Global flags:
  -v, --verbose   Enable debug logging
  -q, --quiet     Log errors only, as JSON lines on stderr
      --version   Print version, commit, and build time, then exit
  -h, --help      Show help for any command

list

List the plugins compiled into the binary.

macfor list plugins
macfor list plugins --json
macfor list plugins --category browser
macfor list plugins --category communication --json

The --json form is stable; safe to feed into a downstream tool that needs to know which collectors are available before invoking collect.

collect

The primary command. Resolves sources, runs plugins, and writes the evidence container.

macfor collect \
  -o, --output <path>              # Required unless --dry-run. Path to the evidence container
                                   #   (.zip is appended if missing).
  [-p, --plugin <id>]              # Repeatable. Collect only the listed plugins.
  [-c, --category <name>]          # Collect every plugin in one category.
  [-f, --from <dir>]               # Collect from a directory tree (e.g. a mounted image)
                                   #   instead of the live system.
  [--image <file>]                 # Collect from a disk image file (DMG, raw, or E01);
                                   #   attached read-only, detached afterwards. v0.2.0+.
                                   #   Can't be combined with --from.
  [--plugin-opt <id>.<key>=<val>]  # Repeatable. Set one option for one plugin. v0.2.0+.
  [--dry-run]                      # Report what would be collected; write nothing.
  [--json]                         # Print the result as JSON on stdout.
  [--record-format <fmt>]          # jsonl (default), parquet, or both.
  [--parquet-compression <codec>]  # snappy (default), zstd, gzip, or none.

Common invocations

# Triage: shell history and Safari, current user
macfor collect \
  --plugin shell.history \
  --plugin browser.safari \
  --output ./triage.zip

# Local user accounts (metadata only; requires root on a live system)
sudo macfor collect --plugin system.users --output ./users.zip

# Full sweep, multi-user (requires root + Full Disk Access)
sudo macfor collect --output ./full.zip

# A volume or directory tree you mounted yourself
macfor collect \
  --from /Volumes/Evidence \
  --output ./evidence-image.zip

# A disk image file: macfor attaches it read-only and detaches it afterwards
macfor collect --image ./suspect.dmg --dry-run
macfor collect --image ./suspect.E01 --output ./evidence-image.zip

# Machine-readable result, records as Parquet
macfor collect --category browser --record-format parquet \
  --output ./browser.zip --json

Disk images (--image)

--image(v0.2.0+) collects from a disk image file without mounting it by hand. macfor detects the format from the file's content, attaches it read-only, collects, and detaches it when collection ends, including after an error. It accepts:

  • DMG, attached with hdiutil.
  • Raw images (dd-style), including an image of a whole GPT-partitioned disk.
  • E01 (EnCase), exposed with ewfmount first. This needs libewf (brew install libewf) and macFUSE.

For a macOS 10.15+ APFS volume group, macfor reads the System and Data volumes as one merged filesystem, as on the running Mac. A volume that doesn't mount, such as a FileVault-encrypted Data volume, isn't collected, and macfor reports a warning. --imageruns on macOS only, and can't be combined with --from. The container records the source as "type": "image" with the image path and format, and the chain of custody records the attach and detach (see the container format spec).

Plugin options (--plugin-opt)

--plugin-opt (v0.2.0+) sets one option for one plugin, as <plugin_id>.<key>=<value> (or <plugin_id>:<key>=<value>). Repeat it for more options. The plugin ID is matched against the plugins in the binary, longest match first, so dotted IDs work with either separator. Each plugin defines its own options; they are listed on its plugin page. A value takes one of these forms:

FormValue used
VALUEThe literal text, recorded verbatim in the container.
env:NAMEThe value of environment variable NAME, which must be set.
file:PATHThe contents of PATH, minus one trailing newline.
literal:VALUEVALUE verbatim, even if it starts with env: or file:.

Pass secrets with env: or file: so they stay out of shell history and ps. The options are recorded in manifest.json (plugin_options) and as a plugin_options chain-of-custody event. Values read from env: or file:, and values of keys that look secret (containing key, token, secret, password, passwd, credential, or auth), are recorded and displayed only as [set].

For example, with the ai.claudedesktop plugin in macfor-pro:

macfor-pro collect --plugin ai.claudedesktop \
  --plugin-opt ai.claudedesktop.skip_content=true \
  --plugin-opt ai.claudedesktop.audit_key=env:CLAUDE_SAFE_STORAGE_PW \
  --output ./evidence.zip

Exit codes

  • 0 — success. The container was written with no errors, or there was nothing to collect: no plugin matched --category, or none applied to the source. In those cases no container is written.
  • 1 — failure: bad flags, an unknown --plugin ID, a fatal error, or an interrupted collection. A container that failed while being written is deleted; after an interruption, treat any file at the output path as unusable.
  • 2 — partial: the container was written, but macfor recovered from one or more artifact errors. The errors are recorded in the container's manifest, chain of custody, and plugin logs.
  • 3 — license refused: a licensed build (macfor-pro) declined to start the collection, for example because the license expired.

manifest

Operate directly on plugin artifacts.yaml manifests — useful for plugin authors and for writing custom triage scripts.

# Validate one or more manifests
macfor manifest validate plugins/*/artifacts.yaml

# Print the resolved on-disk paths a plugin would read
macfor manifest paths --plugin browser.safari
macfor manifest paths --plugin browser.safari --os-version 14.4 --json

# Artifact location catalog: every artifact, its version-aware locations,
# and how it is parsed (declarative / native / planned), per OS and app version
macfor manifest matrix --plugin browser.safari
macfor manifest matrix --markdown
macfor manifest matrix --json

# Write Markdown documentation for every loaded manifest
# into a directory (default: docs/artifacts)
macfor manifest docs --output ./artifact-docs

manifest pack

Out-of-band manifest packs are signed, versioned bundles of artifact manifests that can be distributed and validated independently of the binary. A pack is a directory containing the manifest YAMLs, a pack.yaml (version plus a SHA-256 per manifest), and a detached pack.sig. Packs carry declarative configuration only — they can never reference native parser code — and the embedded plugin manifest remains the source of truth for collection.

# Show a pack's version, digest, and per-plugin content hashes
macfor manifest pack info ./pack-dir

# Sign a pack (writes pack.sig) with an ed25519 private key
macfor manifest pack sign ./pack-dir --key key.hex

# Verify a pack's signature and constraints against a trusted public key
macfor manifest pack verify ./pack-dir --pubkey pub.hex

Logging

macfor uses zerolog. Logs go to stderr. By default they're human-readable; --verbose adds debug detail, and --quiet logs only errors, as JSON lines. Per-plugin logs are also archived inside the evidence container under logs/<plugin_id>/collection.log.