Memories / Documentation

On this page

Unattended desktop CLI and MCP

Unattended access is an explicit, local-only, read-only capability for selected live vaults. It includes ordinary and private memory/cards, original binary files, revision history and explicitly requested credential plaintext. Only enable it when you trust the receiving client with every asset and secret in those vaults. It isn't ordinary MCP authority or a permanent sudo session.

Enroll and select custody

Start the daemon in a separate terminal, using the same dedicated absolute home for every command. Initialize your library and create its vaults normally first. The paths below are examples; use your own private directory on each platform.

memories --home /absolute/private/home daemon

Choose a backend explicitly in your interactive terminal:

memories --home /absolute/private/home unattended enable --backend linux-secret-service

Enrollment warns that clients can read stored passwords, asks you to type ENABLE, then prompts for your local password for unlock and again for sudo. This consent/password setup is required once for enrollment, not on each unattended read. Don't pass passwords through arguments or environment variables. Later management still requires an ordinary password-unlocked, sudo-authorized terminal.

Backend Custody and requirements
windows-dpapi Current-user Windows DPAPI; protected files use owner-only permissions. No machine-wide scope or authentication UI.
macos-keychain Nonsynchronizing macOS Keychain entry; locked or approval-needed access is denied rather than prompting.
linux-secret-service Session-bus Secret Service with an already unlocked collection/item. It doesn't request Unlock or invoke Prompt.
owner-file Explicit lower-protection opt-in on desktop: plaintext wrapping material in an owner-private file, not cryptographic protection against the OS account.

For example, deliberately choosing the lower-protection option uses unattended enable --backend owner-file. There is no automatic fallback when a native backend is unavailable or needs interaction. Secret Service relies on the local OS-account/D-Bus boundary; the client can't control arbitrary provider-specific UI behavior. Backend selection is create-only. Don't edit its metadata to switch backends. Custody binds the canonical store path and current header identity, so copying it to another store isn't enrollment.

The password wrapper remains available for normal unlock and recovery. Enrollment adds a separate master-key wrapper whose wrapping key stays outside the database; it doesn't replace password authentication.

Mint a client file

In the same authorized terminal, mint a grant for the vaults the client needs:

memories --home /absolute/private/home unattended mint --vault VAULT_ID --client-file /absolute/private/home/client.json
# Repeat --vault VAULT_ID to include another vault in this grant.

The parent directory must already exist and be owner-private. Mint publishes the file atomically without overwriting an existing file and rejects unsafe ownership, permissions or links. Failed publication attempts to revoke the new grant and reports revocation failure. Output contains the grant ID and file path, never the bearer token. Keep the ID for revocation.

This client file is separate from ordinary MCP grant files. Protect it like a password; don't print its contents, commit it, or put its token in command arguments. CLI/MCP reads require explicit --client-file selection and the same home/store. Scope is read_only_all_assets for the selected vaults, not a per-asset or ordinary-content-only grant. Each read rechecks current local device membership and vault scope.

Startup and reads

Restart the daemon after enrollment to use keys-only startup. Stop it without issuing memories lock, then start it again with the same home. Successful startup loads unattended keys but reports ordinary unlocked: false: ordinary reads, writes, sudo, cloud work and RAG remain locked until password unlock. Backend failure leaves unattended keys unloaded, with no password or ambient-auth fallback.

On Unix, forced termination can leave service.sock in the home directory. Remove that stale socket only after confirming its daemon has stopped.

memories --home /absolute/private/home unattended list VAULT_ID --client-file /absolute/private/home/client.json
memories --home /absolute/private/home unattended history VAULT_ID ASSET_ID --client-file /absolute/private/home/client.json
memories --home /absolute/private/home unattended read VAULT_ID ASSET_ID --client-file /absolute/private/home/client.json
memories --home /absolute/private/home unattended credential-bytes VAULT_ID CREDENTIAL_ID --client-file /absolute/private/home/client.json

List returns asset metadata, including private, file and credential assets, but not their bodies; tombstones are omitted. History returns revision metadata, including head/deleted/quarantine flags, not credential bodies. A conflicted current asset requires an explicit matching revision. Historical and deleted revisions can be read explicitly, but quarantined revisions are denied. This route reads live-vault history, not recovery archives.

read returns memory/card Content JSON bytes or a file's original bytes. It rejects credentials. credential-bytes accepts only credentials and returns the stored body's UTF-8 bytes, including historical values when explicitly selected. It doesn't add arbitrary binary credential storage. Protected card and wiki secret references remain references; request their referenced credential separately if needed.

Reassemble full bytes

Responses use data containing base64url without padding, with zero-based offset, byte total, next (null when complete), actual revision and encoding (content_json or raw_bytes). To retrieve the full content:

  1. Request offset 0 with --limit between 1 and 65536 bytes (default 65536).
  2. Decode each response's data separately as base64url without padding.
  3. Use next as the next --offset and pin the first returned revision with --revision REVISION_ID on every subsequent request.
  4. Continue until next is null, then concatenate decoded byte ranges in order. Only then decode UTF-8/JSON if applicable; a range can split a UTF-8 character.

For example, a subsequent range uses:

memories --home /absolute/private/home unattended read VAULT_ID ASSET_ID --client-file /absolute/private/home/client.json --revision REVISION_ID --offset NEXT_OFFSET --limit 65536

Use the same options with credential-bytes. Don't concatenate encoded strings or treat the first range as the whole asset. List/history use --offset and --limit between 1 and 100 items (default 100); their pages reflect current state, not a snapshot, so changes between requests can alter ordering and totals.

Connect an AI client through MCP

Configure a separate stdio server command with the same home and client file:

memories --home /absolute/private/home mcp serve-unattended --client-file /absolute/private/home/client.json

It advertises only unattended_list, unattended_history, unattended_read and unattended_credential_bytes. Tool arguments are vault, asset (except list), optional revision (byte reads), offset and limit. Tool results contain the same paged/ranged JSON in MCP text content; full downloads follow the byte-range contract above. There is no asset mutation, execution, administration, sync, backup dump, search/model execution or OTP-counter advancement tool. Reads save signed delivery intents before returning output; audit/storage failures deny it.

Ordinary mcp serve --grant-file is unchanged and still excludes private content, files and credential reads. Neither server inherits terminal sudo. Center-managed stores reject unattended enrollment/startup/use. HTTP/WebSocket, relay RPC, mobile FFI/Share and WebUI can't use unattended authority. Remote flags, environment dial options and saved remote defaults are refused by these commands, even though global remote options appear in executable help.

Credential base64 is encoding, not encryption. Unattended MCP intentionally gives the receiving client secret bytes. AI providers, transcripts, tool logs, caches or plugins can retain or transmit the encoded value or decoded plaintext. Read-only scope prevents mutations through this capability, not disclosure or use of a copied secret elsewhere. Use synthetic secrets for tests.

Lock, resume, revoke and disable

memories --home /absolute/private/home lock

Manual lock clears keys and durably inhibits unattended startup across restarts. Password unlock alone doesn't resume it. If durable writes fail, lock returns an error; don't assume inhibition persisted on an unwritable device. Idle/shutdown cleanup isn't manual inhibition.

Management requires password unlock and sudo in your local terminal:

memories --home /absolute/private/home unlock
memories --home /absolute/private/home sudo
memories --home /absolute/private/home unattended status
memories --home /absolute/private/home unattended resume

Status reports enabled/inhibited state and grant IDs, not tokens. After resume, restart the daemon without manual locking to return to keys-only state. To remove one client or disable all unattended access:

memories --home /absolute/private/home unattended revoke GRANT_ID
memories --home /absolute/private/home unattended disable

Revocation is durable and idempotent. Disable durably disables authority and revokes every grant before backend cleanup. Deleting a client file alone isn't revocation if someone copied it. Lock, revoke and disable can't recall plaintext already delivered; rotate exposed credentials with their provider.

Recovery and validation limits

Unattended wrapper/authority records aren't included in logical exported backups, device pairing or vault synchronization. Restoring a logical backup doesn't restore unattended enrollment. A whole raw local database copy still includes the auxiliary table, and filesystem backups can copy client files or custody material. Same-account processes, OS administrators, process memory, whole-device rollback and secure erasure remain outside the guarantees in SECURITY.md.

Implemented adapters cover Windows DPAPI, macOS Keychain, Linux Secret Service and owner-file custody. Linux end-to-end validation uses owner-file custody with the real daemon, private memory, an original binary file and a synthetic UTF-8 credential. It covers keys-only restart, CLI/stdin-stdout MCP, ordinary/cloud/RAG denial, manual inhibition across restart, resume, revocation and disable. Linux custody tests and an isolated D-Bus protocol fixture provide additional coverage, but the fixture isn't a live desktop keyring test.

Windows/macOS native roundtrips, native locked/approval-needed and no-UI behavior, and live desktop keyring verification remain release gates. Cross-target builds or tests of error translation don't establish those native behaviors. Independent review is pending; passing tests aren't a security audit. See the CLI implementation notes and core contract for focused validation commands.