Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ Use a change for a new feature, a change to user-visible behaviour, a breaking c
5. Implement with the `openspec-apply-change` skill. Mark each task `- [x]` in `tasks.md` when it is done and tested.
6. If the plan changes during work, update the change artifacts with the `openspec-update-change` skill.
7. Before you report completion, run the `openspec-verify-change` skill.
8. After the pull request merges, archive the change with the `openspec-archive-change` skill. Archiving moves it to `openspec/changes/archive/` and updates `openspec/specs/`.
8. Before you create the pull request, archive the completed change with the `openspec-archive-change` skill. Archiving moves it to `openspec/changes/archive/` and syncs its spec deltas into `openspec/specs/`. Archive only when every task is done and step 7 passes.

Use `openspec list` for active changes and `openspec status --change <name>` for artifact status.

Commit OpenSpec artifacts with the code change they describe. Commit the archive move in the pull request that archives a change.
Commit OpenSpec artifacts with the code change they describe. Commit the archive move in the same pull request as the change. A change that is only a proposal stays active until it is implemented.

## Commands

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ agent. Bug reports, fixes, documentation, and new features are all welcome.

## Set up

You need [Bun](https://bun.sh) and Node.js 24. The package itself supports
You need [Bun](https://bun.sh) and Node.js 24. The published package supports
Node.js 22.14 or later.

```bash
Expand Down
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OMMS — Opinionated Modular Memory System
# OMMS: Opinionated Modular Memory System

[![npm version](https://img.shields.io/npm/v/om-memory-system.svg)](https://www.npmjs.com/package/om-memory-system)
[![npm downloads](https://img.shields.io/npm/dm/om-memory-system.svg)](https://www.npmjs.com/package/om-memory-system)
Expand Down Expand Up @@ -26,7 +26,8 @@ the other. Everything is stored locally on your machine.
OpenCode v1.
- **Learns your preferences.** A user profile of your habits builds up over
time and follows you across projects.
- **Imports your past sessions.** Pi and OpenCode import older history after startup. A command provides a preview and manual control.
- **Imports your past sessions.** Pi and OpenCode import older history after
startup. A command gives you a preview and manual control.
- **Lets you look and edit.** A local web page shows every memory and your
profile.
- **Keeps private things private.** Text inside `<private>` tags is never
Expand Down Expand Up @@ -74,6 +75,14 @@ pi install npm:om-memory-system

Restart Pi. You can install OMMS in both agents; they share the same memory.

**Terminal command (optional, recommended).** A global install lets the login
web app and the `om-memory-system` terminal commands run without `npx`:

```bash
npm i -g om-memory-system # or: bun add -g om-memory-system
om-memory-system --version
```

### 2. Choose which model writes memories (optional)

With no settings, OMMS uses the model of the session you are working in. To
Expand All @@ -91,18 +100,22 @@ config file yet, OMMS creates this one with comments on first start.
}
```

You can also use any OpenAI-compatible or Anthropic API with your own key.
See [Configuration](docs/configuration.md#choosing-the-model).
You can also use any OpenAI-compatible or Anthropic API with your own key, set
up on the Settings page's **External API** card, and choose `"external"` as a
host's model. See [Configuration](docs/configuration.md#choosing-the-model).

### 3. Check it works

Work normally for a few turns, then open `http://127.0.0.1:4747` in your
browser. OpenCode or the login web app serves this page. New memories appear on the timeline.
You can also ask the agent: "search memory for what we changed today".
browser. OpenCode or the login web app serves this page. New memories appear
on the timeline. You can also ask the agent: "search memory for what we changed today".

## Import your past history

Older sessions import automatically after a host starts. This makes model calls. To opt out, set `"autoBackfill": false` in `~/.config/omms/omms.jsonc` before starting. For a manual import or custom source, preview inside the agent:
Older sessions import automatically after a host starts. This makes model
calls. To turn it off, set `"autoBackfill": false` in
`~/.config/omms/omms.jsonc` before you start the agent. For a manual import or
a custom source, preview it inside the agent:

```text
/memory-import-opencode-history --dry-run
Expand Down Expand Up @@ -134,6 +147,7 @@ backup first. See [Updating and upgrading](docs/upgrading.md) and
| [Using memory day to day](docs/using-memory.md) | How capture and recall work, the `memory` tool, the user profile |
| [Configuration](docs/configuration.md) | Settings, choosing the model, embeddings, troubleshooting |
| [Web UI](docs/web-ui.md) | The memory explorer, opening it on a network safely |
| [Settings page](docs/web-ui-settings.md) | Every card and control on the web Settings page |
| [Moving projects](docs/moving-projects.md) | Nested repositories, moved folders, backup and restore |
| [Updating and upgrading](docs/upgrading.md) | Updates, pinning a version, older stores |
| [OpenCode adapter](docs/opencode-adapter.md) | How the OpenCode plugin hooks in |
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/007-edit-global-config-from-web-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ If OMMS reads only the legacy `opencode-mem.jsonc`, the first page save copies t

- [Settings page](../web-ui.md#settings-page)
- [Config writer](../../src/services/global-config-writer.ts)
- [OpenSpec design](../../openspec/changes/web-settings/design.md)
- [OpenSpec design](../../openspec/changes/archive/2026-09-27-web-settings/design.md)
4 changes: 2 additions & 2 deletions docs/adr/008-session-first-web-import.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ The Settings page first offered the history importer as a form of CLI flags. Use

## References

- [Importing from the page](../web-ui.md#importing-from-the-page)
- [Importing from the page](../web-ui-settings.md#import-and-backfill)
- [ADR-005](./005-history-import-surfaces-and-model.md), [ADR-007](./007-edit-global-config-from-web-ui.md)
- [TDR-007](../tdr/007-directory-maps-take-precedence.md), [TDR-008](../tdr/008-shared-async-opencode-snapshot.md)
- `src/importer/import-sessions.ts`, `src/importer/import-sources.ts`, `src/importer/import-readiness.ts`, `src/importer/web-import-jobs.ts`
- [OpenSpec design](../../openspec/changes/web-settings/design.md)
- [OpenSpec design](../../openspec/changes/archive/2026-09-27-web-settings/design.md)
2 changes: 1 addition & 1 deletion docs/adr/009-default-on-backfill-and-login-web-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Enable a per-user login item for the standalone web app by default. The item sta

## References

- [Change design](../../openspec/changes/auto-backfill-and-web-autostart/design.md)
- [Change design](../../openspec/changes/archive/2026-09-28-auto-backfill-and-web-autostart/design.md)
- [Configuration](../configuration.md#automatic-history-import-and-login-web-app)
- `src/importer/auto-backfill.ts`
- `src/services/web-autostart.ts`
36 changes: 36 additions & 0 deletions docs/adr/010-private-key-file-for-external-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# ADR-010: Save a pasted external API key to a private key file

**Date:** 2026-09-28
**Status:** Proposed
**Deciders:** OMMS maintainers

## Context

The Settings page gains an External API card so that users can set up an external model (for example a Z.ai GLM endpoint) without editing `omms.jsonc` by hand, and choose it as a host's capture or backfill model with the value `external`. `memoryApiKey` already accepts a literal value, `env://NAME`, or `file://path`. The login web app is started by launchd, systemd, or the Windows Startup folder, which do not load a shell profile, so an `env://` variable set only in `~/.zshrc` does not resolve there. Users still need a way to give the page a key that works in every OMMS process, without the key ending up in the config file, the log, or an API response.

## Decision

The card offers three key sources: an environment variable name (saved as `env://NAME`), the path of an existing key file (saved as `file://path`), and a pasted key. A pasted key is written by the web server to `~/.config/omms/secrets/<name>.key`. The folder is created with mode `700` and the file with mode `600` on macOS and Linux; on Windows both get a user-only access list, using the same code that protects capture traces (moved to `src/services/private-path.ts`). The config then gets `file://` with that path. An existing key file is replaced only after the user confirms. The page never writes a literal key to the config, never logs the request body, and never returns the key. Saving a pasted key is refused on a non-loopback bind without Basic Auth.

An `env://` or `file://` key that does not resolve in a process is treated as not set there, so the card and readiness can report "does not resolve in the web app" instead of the config failing to load.

## Alternatives considered

- **OS keychain.** Needs native code or helper tools on three platforms, and every OMMS process (hosts, CLI, login web app) would need to read it. Rejected for now.
- **Only `env://`.** Does not work in the login web app, which is the main place a user without an open host would configure and run a backfill.
- **Store the literal key in `omms.jsonc`.** The file is often shared or synced, and the page would then write secrets into it. Rejected.

## Consequences

### Positive

- One key source works in every OMMS process, including the login web app.
- The config file and every response hold only a reference.

### Negative

- A key lands on disk in plain text, with the same trust model as the existing `file://` support. File permissions are the only protection.

### Neutral

- Older OMMS versions ignore the key file and read the `file://` reference as before.
47 changes: 47 additions & 0 deletions docs/adr/011-shared-code-never-imports-adapters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# ADR-011: Shared code never imports a host adapter

**Date:** 2026-09-28
**Status:** Proposed
**Deciders:** OMMS maintainers

## Context

OMMS stands for Opinionated Modular Memory System. One shared engine runs behind two hosts, OpenCode and Pi, and each host has a thin adapter in `src/adapters/<host>/`.

Some shared code had started to reach into adapter code:

- `src/importer/profile-import.ts` imported `isInternalPrompt` from the OpenCode adapter.
- `src/importer/importer.ts` and `src/importer/session-loader.ts` imported Pi's conversation parser from the Pi adapter.

Each import worked, but it tied shared code to one host. A new host, or a change inside one adapter, could then break the other host or the shared importer. The boundary tests covered `src/core/` and `src/services/`, not `src/importer/`, so nothing caught it.

## Decision

Dependencies point one way. Adapters may import shared code. Shared code (`src/core/`, `src/services/`, `src/importer/`, `src/types/`) never imports an adapter.

- Code that knows a host's history format is shared, because the importer, the CLI, and the web app all read history without that host running. It lives in `src/importer/`: `opencode-reader.ts` for OpenCode, and `pi-conversation.ts` with `session-loader.ts` for Pi. The Pi adapter imports `pi-conversation.ts` from there for live capture.
- Code that is the same on every host lives in `src/core/`. `src/core/internal-prompt.ts` recognises omms's own summary and profile prompts.
- Host SDKs load only through dynamic `import()`, only when that host's code runs.
- `tests/pi-adapter-boundary.test.ts` fails when any file in `src/core/`, `src/services/`, `src/types/`, or `src/importer/` refers to `adapters/pi` or `adapters/opencode`.

Adding a host means adding `src/adapters/<host>/` and, when it has importable history, a reader in `src/importer/`. The other hosts do not change.

## Consequences

### Positive

- Each adapter can change, or be removed, without breaking shared code or the other host.
- A test enforces the rule, so it cannot quietly erode again.

### Negative

- Host-format readers sit in the importer rather than beside their adapter, so a host's code is in two places.

### Neutral

- `src/services/` still holds OpenCode's own model code (`opencode-provider.ts`, `opencode-sdk-client.ts`, `profile-llm-client.ts`, `user-memory-learning.ts`), which uses OpenCode SDK types. Moving it into the OpenCode adapter is planned as the OpenSpec change `move-opencode-model-code-to-adapter`.

## Alternatives considered

- **Keep host readers in each adapter and let the importer import them.** This is the dependency this ADR removes.
- **A registry that adapters fill at start-up.** The CLI and the login web app read history with no host running, so nothing would register the readers.
2 changes: 2 additions & 0 deletions docs/adr/ADR_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ Local decision records for OMMS maintainers.
| [007](./007-edit-global-config-from-web-ui.md) | Edit the global config from the web UI | 2026-09-27 | Proposed |
| [008](./008-session-first-web-import.md) | Session-first imports from the web UI with pinned selections | 2026-09-27 | Proposed |
| [009](./009-default-on-backfill-and-login-web-app.md) | Default-on history backfill and login web app | 2026-09-27 | Proposed |
| [010](./010-private-key-file-for-external-api.md) | Save a pasted external API key to a private key file | 2026-09-28 | Proposed |
| [011](./011-shared-code-never-imports-adapters.md) | Shared code never imports a host adapter | 2026-09-28 | Proposed |
Loading
Loading