Software Memory Database · Chapter 1 of 3

What the Memory DB remembers

The Software Memory Database is a SQLite file at %LOCALAPPDATA%\MilochApplicationStudio\memory.db. It is MAS' one piece of persistent state across sessions — every package that reaches Rollout leaves a row behind, and every subsequent capture consults it to answer "have I packaged this before?".

4 min read
Applies to v2.0+
Last updated 2026-07-19
PUBLISHED

The Software Memory Database is a SQLite file at %LOCALAPPDATA%\MilochApplicationStudio\memory.db. It is MAS' one piece of persistent state across sessions — every package that reaches Rollout leaves a row behind, and every subsequent capture consults it to answer "have I packaged this before?".

MAS 2.0 uses SQLite exclusively. The SQL-Server-backed provider that existed pre-Sunset is deactivated in the freeware build (§25 in the project's Locked Decisions); the code stays in the repo for reference but the UI never surfaces it.


What each capture writes #

Every completed Rollout produces four related record types in the Memory DB. All four are surfaced on the Home → Recent projects page and referenced by the Reopen this package action.

Record Contents
software_identities The stable identity of the product across versions: name, vendor, UpgradeCode, current version. One row per product; the version rolls forward with each build.
package_records One row per completed Build. Snapshot of the Capture, the PSADT template version used, the workspace path, the produced package name, the detection rules. Multiple package records can attach to one software identity — one per version.
distribution_records One row per Rollout target. If a Ship pushed to both SCCM and Intune, that produces two distribution rows. Records the target profile, the outcome (Completed / Failed / Cancelled), start and end timestamps, any error text.
audit_log Every security-relevant write across all three tables above, appended to a hash-chain (see 650 Audit chain). Includes actor identity (DOMAIN\user), event type, before/after payload for updates and deletes.

How the Reopen flow uses it #

Home → Recent projects lists the most recent 50 package_records. Clicking Reopen on any row:

  1. Loads the workspace path from the record. If the folder still exists, MAS re-attaches to it.
  2. Restores the Capture snapshot from _capture.json (which was written from the same data at Build time). The Capture page reflects the exact fields the packager confirmed originally.
  3. Restores detection rules and the package name from the record.
  4. Lands the user directly on the Rollout drawer with everything staged — a repeat Ship is one click away.

If the workspace folder was deleted (packagers sometimes prune old build artefacts) but the record still exists, Reopen offers to rebuild the workspace from the stored Capture snapshot. That path regenerates the workspace by re-running Build with the recorded inputs.


Lookup on Capture #

Every new capture also consults the Memory DB to detect a repeat. The lookup runs in this order (each stage falls through on miss):

  1. UpgradeCode match. For MSI installers, the UpgradeCode is stable across product versions. A hit means "same product, possibly newer version".
  2. Vendor + Name exact match. Case-insensitive comparison of the extracted publisher and product name.
  3. Vendor + Name fuzzy match. Levenshtein-based fuzzy match for cases where the installer's metadata drifted slightly between versions.
  4. SHA-256 hash match. Byte-identical installer already captured — offers the packager to re-open the existing record instead of starting fresh.

A hit surfaces a This looks like an existing package card on the Capture page with a Reopen action alongside the Continue as new action. Neither is picked automatically — the packager decides whether the capture continues the existing history or forks a new one.


Concurrency and conflict handling #

SQLite is opened in WAL mode with a 30-second busy-timeout. Since MAS 2.0 is a single-machine tool, contention is rare — the only realistic case is a second MAS window (dev + production launched from the same install). MAS uses last-write-wins with a warning when the loaded RowVersion has been superseded, so the operator sees the conflict rather than a silent overwrite.


Backup and restore #

The Memory DB is a plain SQLite file — copying it to another machine works if the other machine has a MAS install that speaks the same schema version. For versioned, hash-chain-preserving backups, use Settings → Database → Backup/Restore — details in 680 Portable Backup and Restore.

Losing the Memory DB is not catastrophic: MAS still runs, every future capture is treated as new, and Recent Projects is empty until the operator ships something. The workspace folders on disk are unaffected — they carry their own _capture.json sidecar and can be re-imported.


What the Memory DB does NOT store #

  • Source installers. The MSIs and EXEs themselves are not kept — only the metadata extracted from them. Re-packaging an old version requires the original installer file.
  • Telemetry. No "packages built per week" table, no aggregate timing measurements sent anywhere. Local-only operation is a Locked Decision (§15).
  • Credentials. SCCM connection strings, Intune client secrets, code-signing PFX passwords all live in the profile files under profiles/<id>.json, encrypted via DPAPI. The Memory DB never sees them.

Up next · Software Memory Database 2 of 3
Audit Log and Hash Chain
Every security-relevant write to the Memory Database leaves an entry in the audit log. Each entry carries a SHA-256 hash linking it to the previous entry. The chain is verifiable from the Settings UI …
→