@vaur94/agz-memory 0.4.0-beta.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ARCHITECTURE.md CHANGED
@@ -1,173 +1,171 @@
1
- # AGZ Memory v9 Architecture
1
+ # AGZ Memory Architecture
2
+
3
+ This document describes the `0.4.0` runtime and SQLite schema v10.
2
4
 
3
5
  ## System Boundaries
4
6
 
5
7
  ```text
6
- OpenCode V2 beta-18743
7
- -> @vaur94/agz-memory-plugin
8
- -> projection -> redaction -> policy -> CaptureEventV1
9
- -> bounded retrieval -> untrusted context
10
- -> @vaur94/agz-memory/core
11
- -> SQLite schema v9 (canonical)
12
- -> FTS5 + graph + revisions + provenance + outbox
13
- -> optional replaceable derived backend (currently none)
14
-
15
8
  OpenCode MCP client
16
9
  -> agz-memory stdio server
17
- -> unchanged nine-tool MCP adapter
18
- -> same core and canonical SQLite database
19
- ```
20
-
21
- The MCP adapter owns tool schemas and text result envelopes. The core owns
22
- transactions, project isolation, capture, lifecycle, retrieval, and outbox.
23
- The plugin owns only exact OpenCode V2 hook/event adaptation. It writes no SQL.
24
-
25
- ## Canonical Storage
26
-
27
- `projects`, `notes`, and `note_edges` preserve the public v8 identities and
28
- fields. Schema v9 adds internal note fields:
29
-
30
- | Field | Invariant |
31
- |---|---|
32
- | `current_revision` | Integer `>= 1` |
33
- | `subject_key` | Optional normalized supersession key |
34
- | `content_hash` | SHA-256 of canonical kind/title/summary/content |
35
-
36
- Additional tables:
37
-
38
- | Table | Purpose |
39
- |---|---|
40
- | `project_bindings` | Explicit OpenCode project/workspace to memory project mapping; stores only path hashes |
41
- | `capture_checkpoints` | Crash-safe session reconciliation progress without transcript text |
42
- | `capture_events` | Bounded redacted idempotent event audit |
43
- | `note_provenance` | Source IDs, extractor/redaction versions, and confidence; no prompt/tool payload |
44
- | `note_revisions` | Full snapshot for every committed note state |
45
- | `index_outbox` | Payload-free at-least-once derived-index queue |
46
-
47
- `schema_state` is the only schema version source and contains exactly `9` after
48
- migration. Foreign keys are enabled during normal operation.
49
-
50
- ## Transaction Invariants
51
-
52
- - Create commits note, provenance, revision, FTS trigger, and outbox together.
53
- - Patch and pin increment revision only when values actually change.
54
- - Hard note delete cascades revision, provenance, edge, and FTS state.
55
- - Project delete queues payload-free backend purge operations before project
56
- cascades, in the same transaction.
57
- - Supersession marks the old note `superseded`, snapshots it, creates the active
58
- replacement, adds a `SUPERSEDES` edge, and writes outbox operations atomically.
59
- - Capture materialization commits the event disposition and note lifecycle in
60
- one transaction.
61
-
62
- The partial unique index on `(project_id, kind, subject_key)` applies only to
63
- active notes with a subject key. Manual MCP notes keep `subject_key = NULL`, so
64
- the existing free-form contract remains unchanged.
65
-
66
- ## FTS And Retrieval
67
-
68
- `notes_fts` is an external-content FTS5 table keyed by `notes.rowid`. Insert,
69
- update, and delete triggers maintain it inside note transactions. Migration
70
- uses FTS `rebuild` and compares note/FTS counts.
71
-
72
- Retrieval channels are bounded:
73
-
74
- | Channel | Candidate limit |
75
- |---|---:|
76
- | Lexical BM25 | 40 |
77
- | Optional semantic | 40 |
78
- | One-hop graph | 30 |
79
-
80
- Weighted reciprocal rank fusion uses `1.00`, `0.80`, and `0.35` channel weights
81
- with constant `60`. Every semantic hit is re-read by `(project_id, note_id)` and
82
- rejected when missing, inactive, cross-project, stale-revision, or hash-mismatched.
83
- Semantic failure falls back to lexical retrieval.
84
-
85
- The injection formatter emits only kind, opaque ID, title, and summary. It
86
- escapes delimiter characters, includes a fixed untrusted-data warning, limits
87
- output to eight cards and 4,800 characters, and never injects full note content.
88
-
89
- ## Capture Pipeline
10
+ -> nine-tool MCP adapter
11
+ -> memory core
12
+ -> SQLite schema v10 (canonical)
90
13
 
91
- The plugin uses the exact `@opencode-ai/plugin@0.0.0-beta-18743` Promise API:
92
-
93
- - `ctx.session.hook("prompt")`
94
- - `ctx.session.hook("context")`
95
- - `ctx.tool.hook("execute.after")`
96
- - `ctx.event.subscribe({ signal })`
97
- - `ctx.session.get({ sessionID })`
98
- - `ctx.session.context({ sessionID })`
99
-
100
- The live event stream is a latency hint, not the canonical ingestion boundary.
101
- Prompt checkpoints and bounded context reconciliation recover missed terminal
102
- events. Event reconnect uses bounded backoff. Plugin cleanup aborts the stream,
103
- disposes hooks, and waits only a bounded period.
104
-
105
- The projection boundary accepts user prompt text and assistant terminal text.
106
- It excludes reasoning, tool arguments/results, attachments, files, shell output,
107
- system/synthetic/skill/compaction parts, paths, diffs, environment values, and
108
- provider state. Tool capture stores only name, terminal status, opaque native
109
- IDs, and a normalized error type.
110
-
111
- Redaction runs before extraction and again inside core. High-risk payloads are
112
- quarantined with `payload_json = NULL`. Raw secret values and hashes are not
113
- stored in capture audit tables.
114
-
115
- ## Binding And Isolation
116
-
117
- Plugin bindings require memory project UUID, OpenCode project ID, optional
118
- workspace ID, and a verified canonical directory. Raw paths are not persisted.
119
- The binding key is:
120
-
121
- ```text
122
- sha256("opencode-v2\0" + projectID + "\0" + workspaceID + "\0" + sha256(realpath))
14
+ OpenCode V2 beta-18743
15
+ -> @vaur94/agz-memory-plugin
16
+ -> explicit project binding
17
+ -> redacted capture and policy
18
+ -> bounded retrieval and untrusted context
19
+ -> the same memory core and SQLite database
20
+
21
+ SQLite outbox
22
+ -> optional derived retrieval backend
23
+ -> disabled in 0.4.0; backend = none
123
24
  ```
124
25
 
125
- Basenames are never project identities. Event location or session location must
126
- match the active plugin instance. Missing, conflicting, moved, or cross-project
127
- bindings disable capture/injection for that callback.
128
-
129
- ## Backup And Migration
130
-
131
- Migration uses `<database>.migration.lock/owner.json`, mode `0700/0600`, with
132
- PID, process-start marker, host, timestamp, target schema, and random owner ID.
133
- A live owner cannot be broken by runtime or admin.
26
+ The MCP adapter owns tool schemas, annotations, and result envelopes. The core
27
+ owns transactions, project isolation, note lifecycle, capture, retrieval,
28
+ backup, migration, and outbox behavior. The plugin owns only OpenCode hook and
29
+ event adaptation. It issues no SQL directly.
134
30
 
135
- Before v8-to-v9 DDL:
31
+ ## Trust And Ownership
136
32
 
137
- 1. Checkpoint WAL and validate source integrity/foreign keys.
138
- 2. Create a unique `VACUUM INTO` snapshot.
139
- 3. Validate the snapshot on a separate connection.
140
- 4. Write SHA-256, byte size, schema, SQLite version, and row counts to a manifest.
141
- 5. Fsync temporary files and the backup directory, then atomically rename.
142
- 6. Rebuild notes/edges, create revision/provenance rows, create v9 tables and
143
- trigger-based FTS, and set schema `9` as the final SQL step.
144
- 7. Re-enable and verify foreign keys, integrity, counts, revisions, and FTS.
33
+ `projects.id` is the ownership boundary. Every note, edge, revision,
34
+ provenance record, binding, checkpoint, and capture event carries or resolves
35
+ to that immutable UUID. Names are unique labels and may change.
145
36
 
146
- Failure closes the candidate DB and restores the verified snapshot. Restore
147
- never overwrites the previous canonical DB; it preserves the old file and
148
- quarantines WAL/SHM sidecars.
37
+ Public selectors accept exactly one of `projectID` or `projectName`. The store
38
+ resolves the selector before any read or mutation. Edge creation verifies that
39
+ both endpoints belong to the selected project. Project deletion relies on
40
+ foreign-key cascades only after the caller supplies the immutable ID, exact
41
+ current name, and fixed confirmation phrase.
149
42
 
150
- ## Outbox
43
+ ## Canonical Schema
151
44
 
152
- Outbox work is FIFO per `(backend, project_id)`. Atomic claims use random worker
153
- lease IDs and expiry. Stale revision upserts complete without export. Vendor
154
- exports apply redaction again and derive a hash from the redacted document.
155
- High-risk manual notes remain canonical but are not exported.
45
+ SQLite schema v10 contains:
156
46
 
157
- Delivery is at least once and adapters must be idempotent by opaque project/note
158
- key. Ten failed attempts move work to `dead`; canonical note commits are never
159
- rolled back by a derived backend outage.
47
+ | Table | Responsibility |
48
+ |---|---|
49
+ | `projects` | Immutable project identity and unique normalized name. |
50
+ | `notes` | Current note state, status, subject key, revision, and content hash. |
51
+ | `note_edges` | Typed same-project graph relations. |
52
+ | `notes_fts` | Trigger-maintained FTS5 projection of current note text. |
53
+ | `project_bindings` | Explicit OpenCode-to-memory mapping with canonical path hash. |
54
+ | `capture_checkpoints` | Bounded reconciliation progress without transcript text. |
55
+ | `capture_events` | Redacted, idempotent capture audit under `agz-memory.capture/1`. |
56
+ | `note_provenance` | Source identity, extractor/redaction versions, and confidence. |
57
+ | `note_revisions` | Immutable snapshot for each committed note revision. |
58
+ | `index_outbox` | Payload-free queue for replaceable derived indexes. |
59
+ | `schema_state` | The single current schema version. |
60
+
61
+ The v10 migration changes product-owned persisted identities. Existing v9
62
+ capture rows are copied with the final capture contract; all other data remains
63
+ in place. Migration runs with foreign keys temporarily disabled inside one
64
+ transaction, reenables them, then requires integrity and foreign-key checks to
65
+ pass.
66
+
67
+ ## Note Lifecycle
68
+
69
+ Manual MCP writes and automatic writes use the same invariants:
70
+
71
+ 1. Normalize and validate the project selector and input.
72
+ 2. Calculate the canonical content SHA-256.
73
+ 3. Commit the note mutation and its provenance/revision in one transaction.
74
+ 4. Maintain supersession status and the `SUPERSEDES` edge when applicable.
75
+ 5. Enqueue identity-only derived-index operations for configured backends.
76
+ 6. Let SQLite triggers update FTS5 for insert, update, and delete.
77
+
78
+ Only active notes are returned by normal recall. Superseded and archived state
79
+ remains auditable through revisions and explicit reads where supported.
80
+
81
+ ## MCP Contract
82
+
83
+ The external contract has exactly nine tools. Single and batch mutations share
84
+ the same validation rules. A batch is ordered but deliberately non-atomic:
85
+ each completed item commits before the next begins, and every item returns its
86
+ own result.
87
+
88
+ Tool descriptions mark read-only, idempotent, and destructive behavior for MCP
89
+ clients. `memory_read` is the only operation that expands indexed cards to full
90
+ content and graph neighbors. `memory_recall` returns bounded cards suitable for
91
+ model context.
160
92
 
161
- ## Fail-Open And Fail-Closed
93
+ ## Capture Pipeline
162
94
 
163
- | Operation | Behavior |
164
- |---|---|
165
- | Plugin capture/injection | Fail-open; OpenCode request continues |
166
- | Semantic query | Lexical fallback |
167
- | Binding conflict | Fail-closed for memory feature |
168
- | Secret quarantine | Fail-closed for note write |
169
- | MCP mutation | Transaction rollback and explicit tool error |
170
- | Migration/restore | Fail-closed; service does not start on partial state |
171
-
172
- Logs contain allowlisted operation/outcome/error codes only. Prompt, query,
173
- note text, paths, tool payloads, headers, and credentials are never logged.
95
+ Capture requires all of these gates:
96
+
97
+ 1. The plugin version and running OpenCode beta match exactly.
98
+ 2. Mode is not `off`, capture is enabled, and exactly one explicit binding
99
+ matches project ID, workspace ID, and canonical directory.
100
+ 3. Only terminal user/assistant text or terminal tool status is projected.
101
+ 4. Credential and private-key patterns are removed or quarantined.
102
+ 5. The strict `CaptureEventV1` parser enforces size, source identity, event
103
+ kind, and redaction metadata.
104
+ 6. A deterministic SHA-256 idempotency key prevents replay duplicates.
105
+ 7. Shadow modes stop at the audit event. `auto-write` continues only for an
106
+ allowed kind, explicit durable evidence, supported intent, and confidence at
107
+ or above policy.
108
+ 8. Content is redacted again before note materialization.
109
+
110
+ Quarantined events never retain a payload. Startup and hourly retention workers
111
+ drain bounded batches: terminal event payloads become eligible for clearing
112
+ after 30 days, quarantined events for deletion after 7 days, and expired idle,
113
+ closed, or unavailable checkpoints for deletion. If every AGZ Memory process is
114
+ stopped at the deadline, overdue work is drained on the next MCP or plugin start.
115
+
116
+ ## Retrieval Pipeline
117
+
118
+ Retrieval starts with project-filtered lexical FTS5 results. Same-project graph
119
+ neighbors can be added with bounded fan-out. A reciprocal-rank fusion step
120
+ deduplicates candidates and returns at most eight cards within the configured
121
+ deadline.
122
+
123
+ The plugin formats cards inside an escaped
124
+ `<agz-memory-context trust="untrusted">` envelope capped at 4,800 characters.
125
+ The envelope states that records are reference data, not instructions or system
126
+ policy. A timeout or retrieval failure produces no injection and leaves the
127
+ original OpenCode context unchanged.
128
+
129
+ Semantic providers implement an optional backend contract: project-filtered
130
+ query, idempotent upsert, deterministic delete, full project purge, and health.
131
+ No provider is enabled in `0.4.0`. The SQLite lexical/graph path remains fully
132
+ functional without one.
133
+
134
+ ## Derived Index Outbox
135
+
136
+ `index_outbox` stores backend, operation, project ID, note ID, revision, and
137
+ content hash. It never stores note text. Workers lease rows, derive content
138
+ from the canonical database at execution time, and acknowledge success only
139
+ after the backend call completes.
140
+
141
+ Leases are reclaimable after expiry. Retries use bounded exponential backoff;
142
+ terminal failures become `dead` and are visible through the admin CLI. Project
143
+ purge is a first-class operation so a derived backend cannot retain deleted
144
+ project content by omission.
145
+
146
+ ## Backup, Migration, And Restore
147
+
148
+ Database upgrades are serialized by a filesystem migration-lock directory with
149
+ an owner record. Before the first schema mutation, AGZ Memory checkpoints WAL,
150
+ creates a SQLite-consistent copy with `VACUUM INTO`, verifies integrity and row
151
+ counts, hashes the bytes, and atomically publishes both database and
152
+ `agz-memory-backup/1` manifest.
153
+
154
+ A failed migration closes the active connection and attempts restore from that
155
+ verified backup. Manual restore is two-step: dry-run inspection, then exact
156
+ SHA-256 and `RESTORE_DATABASE_FROM_VERIFIED_BACKUP` confirmation. The replaced
157
+ database is preserved under a unique failed-source name.
158
+
159
+ ## Failure Policy
160
+
161
+ - Unsupported future schema: fail closed without mutation.
162
+ - Missing or conflicting plugin binding: disable the plugin.
163
+ - OpenCode version mismatch: disable the plugin; MCP remains available.
164
+ - Capture parsing, redaction, or policy failure: reject or quarantine, never
165
+ broaden acceptance.
166
+ - Retrieval timeout/backend error: omit injection and preserve original context.
167
+ - Migration failure: restore verified source or raise an aggregate failure.
168
+ - Dead outbox work: retain canonical SQLite data and report operational state.
169
+
170
+ These rules favor durable canonical data and explicit operator action over
171
+ automatic recovery that could cross a project or trust boundary.
package/CHANGELOG.md CHANGED
@@ -1,18 +1,60 @@
1
1
  # Changelog
2
2
 
3
- ## 0.4.0-beta.1 - 2026-08-31
4
-
5
- - Added verified backup manifests, migration locking, schema v9, restore, and
6
- the `agz-memory-admin` binary.
7
- - Added note revisions, provenance, trigger-maintained FTS5, supersession, and
8
- payload-free derived-index outbox processing.
9
- - Added strict `CaptureEventV1`, deterministic idempotency, double redaction,
10
- quarantine, retention, and explicit high-confidence auto-write policy.
11
- - Added bounded lexical/graph/hybrid retrieval contracts and untrusted context
12
- formatting.
13
- - Added the separate exact-beta OpenCode V2 plugin package with safe `off`
14
- default and staged rollout modes.
15
- - Preserved all nine MCP tool names, selectors, result envelopes, project
16
- isolation, and destructive confirmations.
17
- - Renamed the public repository, packages, binaries, MCP server, and plugin to
18
- AGZ Memory while retaining legacy persisted contract identifiers.
3
+ All notable changes to AGZ Memory are recorded here. The project follows
4
+ [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [0.4.0] - 2026-09-01
7
+
8
+ ### Added
9
+
10
+ - Published the final `@vaur94/agz-memory` MCP/core/admin package and the
11
+ lockstep `@vaur94/agz-memory-plugin` package.
12
+ - Added schema v10 migration for final AGZ Memory persisted contract identity.
13
+ - Added a release-surface verifier for package versions, bilingual section
14
+ parity, final version pins, and retired-name reintroduction.
15
+ - Added final English/Turkish installation, rollout, recovery, architecture,
16
+ contribution, security, and community documentation.
17
+
18
+ ### Changed
19
+
20
+ - Standardized capture events on `agz-memory.capture/1`, backup manifests on
21
+ `agz-memory-backup/1`, and injected records on the escaped
22
+ `<agz-memory-context trust="untrusted">` envelope.
23
+ - Centralized runtime package identity on product version `0.4.0`.
24
+ - Upgraded the canonical SQLite schema from v9 to v10 while preserving all v9
25
+ capture rows and rewriting their contract during migration.
26
+ - Updated every public command, package dependency, configuration sample, and
27
+ release document to exact final version `0.4.0`.
28
+
29
+ ### Security
30
+
31
+ - Kept the OpenCode plugin inert by default: `mode: "off"`, capture disabled,
32
+ no bindings, automatic project creation forbidden, and semantic backend
33
+ `none`.
34
+ - Preserved strict project ownership, destructive confirmation, double
35
+ redaction, payload-free outbox, verified backup, and fail-closed migration
36
+ behavior.
37
+
38
+ ### Compatibility
39
+
40
+ - MCP remains independent of the OpenCode application version.
41
+ - The optional plugin supports exactly OpenCode V2 and `@opencode-ai/plugin`
42
+ `0.0.0-beta-18743`.
43
+ - Final backup manifests are intentionally accepted only under the final AGZ
44
+ Memory format. A prerelease manifest must be handled by the prerelease that
45
+ created it before upgrading.
46
+
47
+ ## [0.4.0-beta.1] - 2026-08-31
48
+
49
+ - Introduced verified backup/restore, migration locking, schema v9, revisions,
50
+ provenance, trigger-maintained FTS5, supersession, and the derived-index
51
+ outbox.
52
+ - Introduced strict capture events, deterministic idempotency, double
53
+ redaction, quarantine, retention, and policy-gated automatic writes.
54
+ - Introduced bounded lexical/graph retrieval and the exact-beta OpenCode V2
55
+ plugin with staged rollout modes.
56
+ - Preserved the nine-tool MCP interface and project-isolation guarantees while
57
+ establishing the AGZ Memory public packages and repository.
58
+
59
+ [0.4.0]: https://github.com/ugur-murat-alt/agz-memory/releases/tag/v0.4.0
60
+ [0.4.0-beta.1]: https://github.com/ugur-murat-alt/agz-memory/releases/tag/v0.4.0-beta.1