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 commandlist
List the plugins compiled into the binary.
macfor list plugins
macfor list plugins --json
macfor list plugins --category browser
macfor list plugins --category communication --jsonThe --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 --jsonDisk 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
ewfmountfirst. 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:
| Form | Value used |
|---|---|
VALUE | The literal text, recorded verbatim in the container. |
env:NAME | The value of environment variable NAME, which must be set. |
file:PATH | The contents of PATH, minus one trailing newline. |
literal:VALUE | VALUE 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.zipExit 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--pluginID, 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-docsmanifest 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.hexLogging
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.