Skip to content

Repository files navigation

Machine Memory

Machine Memory is a persistent, evidence-based history layer for a developer workstation. It answers deterministic questions about what changed on your machine, when, and how — from an immutable, hash-chained log of real events, not inference or guesswork. The hash chain detects accidental corruption and unsophisticated tampering; see Known Limitations for what it does not defend against.

Status: v0.7.0 — local-only. This release tracks changes to your PATH, installed applications, environment variables, Windows services, drivers, certificates, and scheduled tasks, and can correlate related changes into higher-level Operations — each labeled with an explicit evidence tier (Proven/Corroborated/TemporalAssociation/ CoObservation, see Correlation rules below) stating exactly what class of evidence supports it. mm correlate is also the discovery entry point: it surfaces every finding — rule, confidence, evidence tier, evidence count — without requiring an operation_id up front, optionally filtered by --rule-id/ --evidence-tier/--min-confidence, before you drill into mm explain <operation_id>. A mm-agent run continuous background mode and a mm status command exist alongside the original one-shot collection (see docs/10-rfcs/CONTINUOUS-WINDOWS-AGENT.md), and a desktop application now provides a graphical Overview/Changes/ Findings/Investigate/System-Health view over the same data (see Desktop Application below and docs/10-rfcs/DESKTOP-APPLICATION.md). See Scope of v0.5.0 below for what's deliberately still out.

Using a pre-built Windows release ZIP rather than building from source? See the Installation and Operations Guide for the exact extract → run → schedule → upgrade → uninstall workflow. The rest of this README covers building from source and the product's overall shape.

Why PATH?

"Why did my shell suddenly stop finding python?" is a question every developer has actually had, and it's usually unanswerable after the fact. PATH tracking was Machine Memory's first collector and remains its flagship example: every time something is added to or removed from your machine's PATH, it's recorded, permanently, with a timestamp — queryable later with an ordinary CLI command. Six more collectors (installed applications, environment variables, Windows services, drivers, certificates, scheduled tasks) and a correlation engine that groups related changes into named Operations exist alongside it — see Commands below.

Collectors

Collector Resource kind Platform
PATH entries PATH_ENTRY Linux/macOS/Windows
Installed applications APPLICATION Linux/macOS/Windows
Environment variables ENVIRONMENT_VARIABLE Linux/macOS/Windows
Windows services SERVICE Windows only (SCM)
Windows drivers DRIVER Windows only (SCM)
Certificates CERTIFICATE Windows only (CryptoAPI cert stores)
Scheduled tasks SCHEDULED_TASK Windows only (Task Scheduler XML; requires elevation to read C:\Windows\System32\Tasks)

Correlation rules

Rule Claim
ConsecutiveEventsRule A tight, same-kind run of events on one machine
SoftwareInstalledRule An APPLICATION Installed event, at full confidence
ServiceStoppedRule A service transitioned to meaningfully stopped
CertificateExpiryRiskRule A certificate entered its expiry-risk window
PathBrokenRule A PATH_ENTRY was removed, optionally corroborated by a nearby APPLICATION event
CrossResourceCoObservationRule Several heterogeneous Installed events were first discovered together in one real collection run — states co-observation only, never a causal or real-world-timing claim (see the rule's own module documentation for the full analysis)

Quick Start

Prerequisites

  • A stable Rust toolchain (see rust-toolchain.toml for the pinned version)
  • protoc (the Protocol Buffers compiler) — install via your system package manager, e.g. apt install protobuf-compiler (Debian/Ubuntu) or brew install protobuf (macOS)

Build from source

git clone https://github.com/<your-org>/machine-memory.git
cd machine-memory
cargo build --workspace --release

This produces two binaries in target/release/:

  • mm-agent — the collector. Run this to capture the current state of your PATH and record any changes since the last run.
  • mm — the query CLI. Run this to ask questions about what's been recorded.

Run it

# First run: captures your current PATH (and everything else the other
# six collectors observe) as the baseline.
./target/release/mm-agent --machine-id my-laptop

# ...time passes, you install a new tool, your PATH changes...

# Run the agent again: only the delta is recorded, not a full re-scan.
./target/release/mm-agent --machine-id my-laptop

# Now ask questions:
./target/release/mm --machine-id my-laptop timeline
./target/release/mm --machine-id my-laptop diff --range today
./target/release/mm --machine-id my-laptop verify

Neither command needs an explicit --db-path: both default to the same fixed, per-user location (%APPDATA%\machinememory\data.sqlite3 on Windows, $XDG_DATA_HOME/machinememory/data.sqlite3 — falling back to ~/.local/share/machinememory/data.sqlite3 — on Linux/macOS), created automatically on first use. Pass --db-path <file> explicitly if you want a different location (e.g. a portable install, or several machines' histories kept in clearly separate files).

--machine-id (and --db-path, if you're overriding it) must be typed identically across every invocation of both binaries, or you will silently start a second, disconnected history. To make that impossible to get wrong, put them in a config file once and drop the flags entirely:

// Windows: %APPDATA%\machinememory\config.json
// Linux/macOS: ~/.config/machinememory/config.json
// (or point the MM_CONFIG environment variable at any path)
{
  "machine_id": "my-laptop"
}

Both binaries read the same file through the same code path. Explicit flags still win over the config file when given. A malformed config file is a hard error, never silently ignored.

Run it continuously (Windows)

mm-agent run runs collection cycles on a repeating interval (default 30 minutes) until stopped — no separate scheduler needed:

.\target\release\mm-agent.exe --machine-id my-laptop run

It runs an initial cycle immediately, writes an operational status file next to the database, and logs to a rotating file alongside it. Check on it with:

.\target\release\mm.exe --machine-id my-laptop status

To have it start automatically at logon, register it with Windows Task Scheduler:

.\target\release\mm-agent.exe --machine-id my-laptop service install
.\target\release\mm-agent.exe service status
.\target\release\mm-agent.exe service uninstall   # removes the task only, never the database

See docs/10-rfcs/CONTINUOUS-WINDOWS-AGENT.md for the full design (why Task Scheduler over a native Windows Service, single-instance safety, failure semantics, and known limitations — this is the background-execution mechanism, not yet a polished installer).

Run it daily without thinking about it (Linux/macOS)

mm-agent run-once (the default when no subcommand is given) is a one-shot tool by design — it does not run continuously in the background. On Linux, a simple systemd user timer works well:

# ~/.config/systemd/user/machinememory.service
[Unit]
Description=Machine Memory PATH collector

[Service]
Type=oneshot
ExecStart=%h/.local/bin/mm-agent --machine-id %H --db-path %h/.local/share/machinememory/data.sqlite3
# ~/.config/systemd/user/machinememory.timer
[Unit]
Description=Run Machine Memory collector periodically

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target
systemctl --user enable --now machinememory.timer

A macOS (launchd) equivalent is not yet packaged — run mm-agent manually, or adapt the above pattern. (This is unrelated to the SCHEDULED_TASK collector, which observes existing scheduled tasks on the machine — it does not create one for mm-agent.)

Commands

Command Answers
mm timeline What changed, in order
mm diff --range yesterday|today What was added/removed/modified in a time range
mm history --key <path> The full history of one specific PATH entry
mm verify Has this history's hash chain been corrupted or naively tampered with? (see Known Limitations)
mm replay Walk the raw log from the beginning, showing the actual hash-chain linkage
mm stats Aggregate shape of the log: counts, first/last event, chain status
mm correlate [--rule-id <id>] [--evidence-tier <tier>] [--min-confidence <f>] Discover findings: run the correlation rules over the full history, persist, and print every resulting Operation with its rule, confidence, evidence tier, and evidence count — no operation_id needed up front. Excludes a finding whose evidence is entirely a fresh machine's initial baseline discovery (see below); mm explain still resolves any Operation by id regardless
mm explain --operation-id <id> Why was this Operation concluded? Shows the rule, confidence, evidence tier, and the exact evidence events
mm investigate --range today What changed, what correlates, what doesn't, and why — one coherent investigation combining the above instead of stitching five commands together by hand
mm compact Reclaim space: remove raw Events superseded by a later event for the same resource that no persisted Conclusion still cites as evidence — every Operation stays fully explainable via mm explain forever (see docs/03-architecture/RETENTION.md)
mm status Is continuous monitoring running right now (a real, live process check — never inferred from a stale file), and when did any collection (manual or continuous) last complete? See docs/10-rfcs/CONTINUOUS-WINDOWS-AGENT.md §16

Baseline vs. genuine change. A collector's very first run against a machine has nothing to compare against, so it reports every currently-observed resource as Installed — this is necessary (there is no other way to learn what already exists), but it is not a burst of recent real-world installs. mm stats/mm timeline/mm correlate mark such events is_baseline: true (derived from existing collection_run_id data — no schema change), and discovery-oriented findings (mm correlate's findings, mm investigate's correlated_findings) exclude a Conclusion whose evidence is entirely baseline discovery. See docs/10-rfcs/PRODUCT-CORRECTNESS-BASELINE-AND-STATUS.md for the full model.

Every command supports --format text|json — JSON output is a stable, versioned schema suitable for scripting. mm verify and mm replay exit 2 when they detect an integrity violation (and 0 when the history is intact, 1 if the command itself failed), so mm verify && ... composes in scripts the way git fsck does.

Desktop Application

desktop/ is a Tauri v2 + React/TypeScript desktop application — a presentation/orchestration layer over the exact same Rust crates the mm CLI uses (it calls machinememory_cli::run directly, in-process; it never shells out to mm and parses text, and never opens SQLite itself). See docs/10-rfcs/DESKTOP-APPLICATION.md for the full architecture.

Screens: Overview (is monitoring active, last/next collection, recent activity, findings count, history health), Changes (filterable event timeline), Findings (discovered Operations with evidence tier and confidence, click through to a detail view backed by mm explain), Investigate (a UI over mm investigate's time-window semantics), and System / Health (agent status, staleness, integrity verification).

Developer commands:

cd desktop
npm install
npm run tauri dev      # development: Vite dev server + hot reload, requires the dev server running
npm run tauri build    # production: bundled frontend, no dev server, no localhost dependency

npm run tauri build is the only correct production build command. A bare cargo build --release --bin mm-desktop is not sufficient by itself — it produces a binary Tauri still treats as a dev build (it always tries to load http://localhost:1420 and fails with ERR_CONNECTION_REFUSED once no dev server is running), because the tauri/custom-protocol Cargo feature the CLI enables automatically was never passed. desktop/src-tauri/build.rs now hard-fails any --release build missing that feature, so this mistake fails loudly at compile time instead of shipping a broken binary; see docs/10-rfcs/DESKTOP-APPLICATION.md §26 for the full investigation. If you need a raw Cargo build without the full Tauri CLI (e.g. in CI), use cargo build --release --bin mm-desktop --features custom-protocol after npm run build has produced desktop/dist.

npm run tauri build produces three artifacts: the standalone executable (target/release/mm-desktop.exe — what you launch directly to run the app unpackaged) and two installers (target/release/bundle/msi/*.msi, target/release/bundle/nsis/*-setup.exe) — neither installer is signed or polished yet (see the RFC's known limitations).

The desktop app resolves its machine_id/db_path through the exact same config file (machinememory-config) mm/mm-agent use, so all three agree on where a machine's history lives. It can run one-shot collection on demand ("Run collection now", spawning the real mm-agent.exe run-once), but does not start/stop the continuous mm-agent run background process in this release — see the RFC's §10/§24 for why, and for the current, honest state of Windows Task Scheduler background registration (blocked by policy on some corporate-managed machines; the app surfaces this rather than hiding it).

Scope of v0.5.0

This release ships seven collectors (see Collectors above) and a Signature Tier correlation engine with six rules (see Correlation rules above; mm correlate/mm explain) — see docs/03-architecture/CORRELATION-ENGINE.md for exactly what "correlation" means today versus what's still unbuilt.

mm compact (see docs/03-architecture/RETENTION.md) bounds Raw Fact Log growth for superseded, unreferenced history — but this is a narrower guarantee than "retention is solved":

Deliberately, this release does not include:

  • Capability inference, Resource Graphs, generalized/probabilistic correlation, or any AI/NL interface — those are real, planned, and explicitly out of scope until there's real daily-use evidence they're needed.
  • Packaging (no .deb, Homebrew, or installer) — build from source.
  • Projection Store compaction — persisted Operations, Conclusions, and CorrelationCandidates are never removed and grow without bound; only the Raw Fact Log is compacted.
  • Any retention duration or automatic scheduling — mm compact is a command an operator runs, not an invented time-based policy.

Known Limitations

  • Every query currently reads a machine's entire history into memory. Measured on a real Windows development workstation with ~940 real persisted events (baseline scan across all seven collectors): every mm command, including correlate and investigate, completed in well under a second. This is a known, accepted, structural limitation for v0.2.0, not a silent gap — it has not been measured at the scale of years of continuous collection (tens of thousands of events), and nothing bounds that growth (see below).
  • macOS PATH collection is written but not execution-verified. Linux (via /etc/environment) and Windows (registry, SCM, CryptoAPI, and Task Scheduler — all seven collectors) have been run and proven end-to-end on real machines, including agent re-runs reconstructing baselines from persisted history, correlation, explain, investigate, and live tamper detection against an out-of-band-modified database. The Windows-service, driver, certificate, and scheduled-task collectors are Windows-only by design (no equivalent concept on Linux/macOS to collect). The macOS (/etc/paths) code path compiles and is believed correct but has not been run on that platform.
  • SCHEDULED_TASK collection requires an elevated process to read C:\Windows\System32\Tasks. Running mm-agent unelevated is not an error — that one collector is skipped and reported as such in the exit summary, while the other six still run normally.
  • History is retained indefinitely. No compaction or retention policy is implemented yet.
  • The hash chain is not tamper-proof against an attacker who has write access to the database file. mm verify reliably catches accidental corruption and unsophisticated tampering (e.g. hand-editing a row without also recomputing every hash after it). It cannot catch an attacker who recomputes the whole chain forward after modifying it — record_hash is an unkeyed, public function, so anyone with write access to the file can regenerate a fully self-consistent forged chain that mm verify will still report as VERIFIED. This is a structural property of any self-contained hash chain (the same limitation a Git repository's own commit history has against someone with filesystem access to .git), not a bug in the hash algorithm or verification logic. Closing it for real requires an external trust anchor — a reference to a known-good chain tip kept somewhere the attacker doesn't also control — which does not exist in this release. Full analysis: docs/05-security/THREAT-MODEL.md.

Architecture

The full architecture — domain model, subsystem contracts, ADRs, and design rationale — lives in docs/. It's written for contributors and maintainers, not end users; if you just want to use Machine Memory, this README is enough.

Contributing

See docs/08-contributing/ (in progress). Issues and pull requests welcome.

License

MIT — see LICENSE.

About

Machine Memory is an event-sourced change intelligence platform that continuously records machine state, builds a tamper-evident history of changes, correlates related events into evidence-backed findings, and provides timeline, investigation, and explainability tools for understanding what changed, when it changed, and why it matters.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages