# Windows executable distribution

MemPlumb ships a portable Windows x64 product as a Node single-executable application (SEA). The executable contains the MemPlumb Runtime, bilingual MemoryOps console, SQLite engine, HTTP server, PostgreSQL client, CLI, policy/evaluation tools, and semantic-index lifecycle commands. End users do not need Node.js, Docker, or the source repository for the local SQLite console. The executable is a full product surface, not a UI-only demonstration; TypeScript/Python SDKs and other clients call the same daemon contract.

## Use the portable executable

For ordinary local use, double-click `memplumb.exe` or run it without arguments:

```powershell
.\memplumb.exe
```

The executable starts or reuses a hidden local SQLite Runtime and opens the bilingual console. It begins at `127.0.0.1:6066`, probes up to the next 19 ports, and uses the first free one. A process already using a port but not proven to be the launcher-owned Runtime is left untouched. If an older pre-launcher MemPlumb daemon still owns `6066`, either stop it manually before launching or allow v0.13.2 to open on `6067`.

The explicit lifecycle commands are:

```powershell
.\memplumb.exe console
.\memplumb.exe console --no-open
.\memplumb.exe console --durability strict
.\memplumb.exe console-stop
```

`console --no-open` starts or reuses the Runtime without opening a browser and returns a 60-second, single-use authorized URL for manual opening. The same fallback is returned if an automatic browser launch fails. An explicit `--durability strict` request replaces an owned `balanced` Runtime rather than silently reusing the weaker setting. `console-stop` only stops a process after its stored credential, local instance identity, process ID, Workspace, and database profile prove ownership; it never kills an unrelated occupant merely because the port or process ID matches.

The default launcher files are scoped to the current Windows profile:

- Database: `%USERPROFILE%\.memplumb\memplumb.db`
- Sensitive state: `%USERPROFILE%\.memplumb\run\<profile-id>.json`
- Bounded log: `%USERPROFILE%\.memplumb\logs\<profile-id>.log`

The state file contains the reusable local credential and relies on the Windows user-profile ACL. Treat it like an API key: do not upload, share, or include it in diagnostics. Runtime logs exclude the credential, rotate at 2 MiB, and retain one previous `.log.1` file.

The launcher passes the credential through the child Runtime environment rather than the MemPlumb command arguments. It is absent from URLs, browser-launch arguments, logs, and command output. For each Console launch, the authenticated launcher mints a separate token that expires after 60 seconds and can be exchanged only once. Only this disposable token enters the URL fragment and browser-launch arguments. With `--no-open` or after a browser-start failure, the launcher returns the short-lived URL in command output for manual opening; protect that output until the token is used or expires. A successful automatic launch returns only the clean URL. The console removes the fragment from the address bar and history entry, exchanges the token, and saves the returned credential to `sessionStorage` before connecting.

Advanced CLI and daemon commands remain available and unchanged:

```powershell
.\memplumb.exe version --json
.\memplumb.exe doctor --json
.\memplumb.exe init
.\memplumb.exe serve --port 6060
```

`serve` is the explicit path for a foreground daemon, fixed port, PostgreSQL, managed authentication, or deployment automation. `doctor` checks the executable/runtime contract, storage connectivity, schema readiness, Workspace, durability mode, and configured provider types without returning credentials.

The v0.13.2 executable exposes the same Cohort freshness workflow as the source CLI and HTTP/SDK clients:

```powershell
.\memplumb.exe cohort-plan-check --plan rcp_... --maximum-age-seconds 604800 --json
.\memplumb.exe release-create --policy policies\candidate.json --write-quality-cohort-plan-id rcp_... --write-quality-maximum-evidence-age-seconds 604800 --output release.json
```

The first command atomically compares the Plan with the complete current eligible population and reports only added/removed/changed/unchanged counts, age, validity, and hashes; it never prints the corresponding Case IDs. The same privacy-safe view is available in the bilingual Cohort Plan Console. Seven days is the default maximum evidence age.

Memory Store Contract v20 uses SQLite schema v26 and PostgreSQL migration v32. SQLite supports portable postings, Actor-bound ingest idempotency fencing, a revision-fenced embedding cache, retrieval adjudication/evidence controls, quality review coordination, Memory State Snapshots, Memory Cases, durable Replay Runs, Store-native Replay Cohort Plans, and atomic Cohort freshness, but no production ANN. A `context-hybrid-ann.json` Runtime therefore fails closed on SQLite by default; `portable_fallback` can run only with explicit degraded evidence. Production HNSW requires PostgreSQL with `pgvector` 0.8 or newer provisioned on the database host. The executable includes the client and lifecycle logic, not the PostgreSQL extension binary.

```powershell
.\memplumb.exe semantic-index-provision --store postgres --embedder openai-compatible --embedding-model production-embedding-model --embedding-dimensions 1536 --json
.\memplumb.exe semantic-index-backfill --store postgres --embedder openai-compatible --embedding-model production-embedding-model --embedding-dimensions 1536 --json
.\memplumb.exe semantic-index-status --store postgres --embedder openai-compatible --embedding-model production-embedding-model --embedding-dimensions 1536 --json
.\memplumb.exe semantic-index-benchmark --store postgres --embedder openai-compatible --context-policy policies\context-hybrid-ann.json --json
```

Provisioning attempts privileged extension/DDL work; production deployments should run it with an administrator-controlled role, then run the daemon with ordinary Runtime permissions.

Verify the downloaded artifact before first use:

```powershell
Get-FileHash .\memplumb.exe -Algorithm SHA256
Get-Content .\SHA256SUMS
```

The digest must equal both `SHA256SUMS` and `manifest.json.sha256`.

## Build and acceptance gate

Windows x64 builds must run on Windows x64. Node uses the exact runtime binary that produces the SEA blob as the executable injection target.

```powershell
npm ci
npm run build:windows
npm run test:windows
npm run test:windows:reproducible
```

`build:windows` bundles the full dependency graph into CommonJS, disables snapshots and V8 code cache, disables runtime execution-argument extension, creates the SEA, and emits:

- `dist/memplumb-VERSION-windows-x64/memplumb.exe`
- `manifest.json` with version, target, build identity, exact Node version, dependency-lock digest, bundle digest, artifact digest, size, and signing state
- `SHA256SUMS`
- `README.txt`

For v0.13.2, `test:windows` must verify the manifest digest, copy only `memplumb.exe` into a fresh temporary directory, inject an invalid `NODE_OPTIONS` value, and prove that version reporting, default-disabled and configured/redacted OpenTelemetry `doctor`, launcher start/reuse/stop, bilingual Console bootstrap including Cohort freshness, SQLite ingestion/context retrieval, a real two-Case/two-shard Plan, `cohort-plan-check`, and Release Artifact v12 work without leaking restricted eligibility/source/evaluator evidence or freshness Case IDs. The gate also retains v8-v11 artifact verification compatibility. This prevents accidental dependencies on the repository, installed Node runtime, Docker, or ambient Node flags.

When `MEMPLUMB_TEST_POSTGRES_URL` is set, the same clean-directory gate also migrates a real PostgreSQL database, checks readiness, and writes memory through the bundled PostgreSQL client. That proves PostgreSQL packaging, not `pgvector` semantic quality. A release that advertises `hybrid_ann` additionally needs `semantic-index-benchmark` against the target extension/profile; the SQLite smoke and portable candidate gate cannot substitute for it.

`test:windows:reproducible` performs a second clean build and requires identical artifact SHA-256, bundle SHA-256, and content-derived Build ID. `npm run release:windows` runs all three gates in order.

Set `SOURCE_DATE_EPOCH` to include a deterministic `built_at` value. Without it, `built_at` is `null`; build identity is content-derived rather than wall-clock-derived. Reproducing an exact digest also requires the same Node binary, architecture, locked dependencies, and source tree.

## Signing boundary

Local builds are deliberately labeled `unsigned-development-artifact` in the manifest. A SHA-256 digest proves byte integrity, but it does not establish publisher identity or remove Windows SmartScreen warnings.

Authenticode publisher signing and Memory Policy release signing are separate controls. Release Artifact v12 binds a freshness `valid_until`: `release-sign` refuses it after expiry, trusted Runtime/rollout loading rejects it, and a long-running canary atomically disables an expired candidate before routing new work. Authenticode does not extend that evidence window. Artifact v8-v11 deployment verification remains compatible under their original contracts.

Public release automation must Authenticode-sign `memplumb.exe` after SEA injection, timestamp the signature, verify it with `signtool verify /pa`, then regenerate the artifact hash and mark the release manifest as signed. The signing certificate and timestamp service are external release credentials; development builds must never claim this gate passed.

Node SEA is still marked active development in Node 24. Pin the Node patch version in release automation and rerun the clean-directory gate for every runtime upgrade.
