@agentproto/memory 0.0.0 → 0.1.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/README.md CHANGED
@@ -7,7 +7,8 @@ lifecycle (`active`, then `superseded` or `archived`), stored as markdown
7
7
  with YAML frontmatter.
8
8
 
9
9
  Spec: <https://agentproto.sh/docs/aip-72>. This package covers the
10
- document only; a store port and per-harness projection come later.
10
+ document (sections 1 to 7) and the store (section 8); the per-harness
11
+ projection (section 9) lives with the hosts.
11
12
 
12
13
  ## Usage
13
14
 
@@ -45,6 +46,80 @@ const { ok, errors, warnings } = validateMemory(doc)
45
46
  active) and an absent `body` as `""`. Lifecycle helpers: `memoryStatus`,
46
47
  `isAllowedStatusTransition`, `isInForce`.
47
48
 
49
+ ## Store
50
+
51
+ `MemoryStore` (alias `IMemoryStore`) is the section 8 port: `write`
52
+ (`propose` or `commit`), `read`, `list`, `search`, `supersede`, `archive`,
53
+ `dismiss`. `FilesMemoryStore` implements it over the reference layout:
54
+
55
+ ```
56
+ <root>/items/<type>/<id>.md one memory/v1 item per file
57
+ <root>/proposals/<sha256>.md pending proposals, not items
58
+ ```
59
+
60
+ ```ts
61
+ import { FilesMemoryStore } from "@agentproto/memory"
62
+
63
+ const store = new FilesMemoryStore({ root: ".agentproto/memory" })
64
+ const rec = await store.write(item, { mode: "commit" }) // assigns an id
65
+ await store.archive(rec.item.id!, { ifRevision: rec.revision })
66
+ const hits = await store.search("pnpm") // in-force items by default
67
+ ```
68
+
69
+ - `revision` is the SHA-256 of the file bytes. A commit that changes an
70
+ item, `supersede` and `archive` need the current `ifRevision`, else they
71
+ reject with `MemoryConflictError`; an equal re-write is a no-op.
72
+ - `supersede` and `archive` rewrite the `status` line only; no item file
73
+ is ever deleted. Other failures: `MemoryNotFoundError`,
74
+ `MemoryTransitionError` (e.g. `superseded` to `active`),
75
+ `MemorySlugTakenError`, and `MemoryValidationError` naming the field.
76
+ - `search` matches title, description and body. Pass `knowledge` (any
77
+ AIP-10 `IKnowledgeProvider`, typed structurally so this package does not
78
+ depend on the knowledge engine) to merge its hits: a hit naming an item
79
+ of the store (`metadata.memoryId` or its `sourceId`) is checked against
80
+ the files, anything else comes back as `source: "knowledge"`.
81
+
82
+ ## Daemon tools and spawn digest
83
+
84
+ The agentproto daemon (`@agentproto/runtime`) serves a `FilesMemoryStore`
85
+ as MCP tools: `memory_search`, `memory_list`, `memory_read` and
86
+ `memory_write` (default mode `propose`) for every caller, and a `commit`
87
+ mode plus `memory_supersede`, `memory_archive` and `memory_dismiss` for the
88
+ operator or a supervisor session only. Its default root is
89
+ `~/.agentproto/memory` (daemon config `memory.root`). An agent whose
90
+ AGENT.md binds memory (`memory.enabled: true`, `store` or `anchors`) also
91
+ gets the section 9 digest of its in-force, in-scope items appended to its
92
+ system prompt at spawn. See the runtime README's MCP tool surface.
93
+
94
+ ## Native memory (claude-code)
95
+
96
+ An adapter declaring `capabilities.memory { inject: "native-dir", capture:
97
+ "native-dir-diff" }` (claude-code) gets the same in-force items written into
98
+ its own memory dir instead of the system prompt:
99
+
100
+ - The dir is `<session config dir>/memory`, pinned through
101
+ `autoMemoryDirectory` in the session's isolated `settings.json`
102
+ (`~/.agentproto/adapter-config/<lineage>/memory`). The user's real
103
+ `~/.claude` is never written.
104
+ - One topic file per item, `agentproto_<slug>.md`, with the native
105
+ frontmatter plus `metadata.agentprotoId`, `agentprotoSlug` and
106
+ `agentprotoSha`. The index lines live in one fenced block at the top of
107
+ `MEMORY.md` (`<!-- agentproto:begin -->` ... `<!-- agentproto:end -->`),
108
+ bounded well under the CLI's 200 lines / 25KB cut and ending with the
109
+ number of items left out. Lines and files the agent wrote are not
110
+ touched; every spawn rewrites only the block and the `agentproto_*` files.
111
+ - Fallback: when auto memory is off (`CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`, a
112
+ repo `.claude/settings*.json` with `autoMemoryEnabled: false`) or the repo
113
+ pins its own `autoMemoryDirectory`, nothing is projected and the digest
114
+ rides the system prompt. Never both.
115
+ - Capture: at each turn end and at exit the daemon diffs the dir against
116
+ the spawn snapshot (`.agentproto-memory.json`) and writes every new or
117
+ changed native file to the agent's store as a proposal (`memory/v1`,
118
+ `provenance.source: native-memory`, `capture.mode: live`). An edited
119
+ projected file is a proposal on the same `id`, a deleted one a proposal
120
+ with `status: archived`. Nothing is committed; a file is proposed once
121
+ per content. Sandbox sessions are not captured yet.
122
+
48
123
  ## License
49
124
 
50
125
  Apache-2.0. See [LICENSE](./LICENSE).
package/dist/index.d.ts CHANGED
@@ -16,10 +16,14 @@ declare const MEMORY_STATUSES: readonly ["active", "superseded", "archived"];
16
16
  /** Lifecycle status. Absent means `active` (AIP-72 rule 9). */
17
17
  type MemoryStatus = (typeof MEMORY_STATUSES)[number];
18
18
  interface MemoryAnchor {
19
- kind: "global" | "project" | "task" | "session" | "pr" | "contact" | "agent";
19
+ kind: "global" | "project" | "task" | "session" | "pr" | "contact" | "agent" | "node" | "operator";
20
20
  /** Anchor target slug (project, contact, agent). */
21
21
  slug?: string;
22
- /** Anchor target id (task, session). */
22
+ /**
23
+ * Anchor target id (task, session, node, operator). A node's is its
24
+ * AIP-34 id (`@<owner>/<slug>`), an operator's the body of its AIP-54
25
+ * `operator:` ref (`<slug>` or `<slug>@<workspace>`). Section 10.
26
+ */
23
27
  id?: string;
24
28
  /** Repository `owner/name` for a pr anchor. */
25
29
  repo?: string;
@@ -155,6 +159,14 @@ interface ValidateMemoryOptions {
155
159
  * section 2 (`kind` set), rules 1, 2, 4 and 5 as errors, rule 8 as
156
160
  * warnings. Rules 6 and 7 compare two versions of an item and belong to
157
161
  * the store; `isAllowedStatusTransition` covers rule 7's table.
162
+ *
163
+ * Defaults: MEMORY.schema.json gives `tags` (and `evidence.anchorsResolved`,
164
+ * `evidence.flags`) `default: []`, and the generated zod carries it. This
165
+ * function only checks: it never returns the parsed data, so the default
166
+ * is never filled in. An item without `tags` stays without `tags` and
167
+ * reads as untagged (the digest treats it as `global`, AIP-72 section 9).
168
+ * An explicit `tags: []` validates: rule 4 rejects empty strings and empty
169
+ * objects, not empty arrays, though a writer omits it (`defineMemory`).
158
170
  */
159
171
  declare function validateMemory(doc: unknown, opts?: ValidateMemoryOptions): MemoryValidationResult;
160
172
 
@@ -176,9 +188,13 @@ declare function parseMemory(markdown: string): MemoryDocument;
176
188
  *
177
189
  * Every string value is double-quoted, so a YAML 1.1 or 1.2 reader
178
190
  * reads it back as a string (rule 3); undefined fields are omitted
179
- * (rule 4); key order is the document's own, so a status-only rewrite
180
- * changes only the `status` line (rule 6). `parseMemory(renderMemory(d))`
181
- * deep-equals `d`.
191
+ * (rule 4); key order is the document's own. So re-rendering a file this
192
+ * function wrote, with only `status` changed, changes only the `status`
193
+ * line (rule 6). That does not hold for a file another writer produced
194
+ * (unquoted strings, other key styles, comments): re-rendering it
195
+ * normalizes every line, which is why the store rewrites the status line
196
+ * in place instead (`setStatusLine`, `files-store.ts`).
197
+ * `parseMemory(renderMemory(d))` deep-equals `d`.
182
198
  */
183
199
  declare function renderMemory(doc: MemoryDocument): string;
184
200
 
@@ -273,6 +289,8 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
273
289
  pr: "pr";
274
290
  contact: "contact";
275
291
  agent: "agent";
292
+ node: "node";
293
+ operator: "operator";
276
294
  }>;
277
295
  slug: z.ZodOptional<z.ZodString>;
278
296
  id: z.ZodOptional<z.ZodString>;
@@ -323,6 +341,8 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
323
341
  pr: "pr";
324
342
  contact: "contact";
325
343
  agent: "agent";
344
+ node: "node";
345
+ operator: "operator";
326
346
  }>;
327
347
  slug: z.ZodOptional<z.ZodString>;
328
348
  id: z.ZodOptional<z.ZodString>;
@@ -345,6 +365,292 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
345
365
  body: z.ZodOptional<z.ZodString>;
346
366
  }, z.core.$strict>, z.ZodUnion<readonly [z.ZodAny, z.ZodAny]>>;
347
367
 
368
+ /**
369
+ * AIP-72 section 8: the memory store port.
370
+ *
371
+ * The shapes below are the ones section 8 fixes, name for name. A store
372
+ * keys items by `id`; `slug`, when present, is a second handle that is
373
+ * unique among active items (rule 14). Writes are compare-and-set on the
374
+ * opaque `revision` (rule 17), and nothing is ever hard deleted (rule 16).
375
+ */
376
+ /** One stored item, or one pending proposal. */
377
+ interface MemoryRecord {
378
+ item: MemoryDocument;
379
+ /** Opaque; changes on every byte change of the stored document. */
380
+ revision: string;
381
+ /** Set on a proposal, absent on an item. */
382
+ proposalId?: string;
383
+ }
384
+ /**
385
+ * AIP-72 section 10. Built by the host from the calling session, never by
386
+ * the store, and handed in on every operation made on a session's behalf.
387
+ * A call with no `scope` is a host call (rule 30).
388
+ */
389
+ interface MemoryScope {
390
+ /**
391
+ * The node projection: AIP-34 node ids, nearest first, already cut at a
392
+ * sealed or hard node. Empty: the session has no node scope.
393
+ */
394
+ readonly nodes: readonly string[];
395
+ /** Id of the root node of the session's tree. */
396
+ readonly tree?: string;
397
+ /** The operator anchor id, when the session runs an operator. */
398
+ readonly operator?: string;
399
+ }
400
+ interface MemoryFilter {
401
+ type?: MemoryType | readonly MemoryType[];
402
+ status?: MemoryStatus | readonly MemoryStatus[];
403
+ /** Matches at most one active item (rule 14, rule 20 overlap). */
404
+ slug?: string;
405
+ /** Match any, e.g. `["global", "project:acme"]`. */
406
+ tags?: readonly string[];
407
+ /** Rules 10 and 11, at the store's clock. */
408
+ inForce?: boolean;
409
+ /** List proposals instead of items. */
410
+ proposals?: boolean;
411
+ /** Section 10: only the items in the scope's node projection. Absent: a host call. */
412
+ scope?: MemoryScope;
413
+ }
414
+ interface MemorySearchHit {
415
+ source: "memory" | "knowledge";
416
+ /** REQUIRED when `source` is `"memory"`. */
417
+ id?: string;
418
+ slug?: string;
419
+ title: string;
420
+ snippet?: string;
421
+ score?: number;
422
+ /** Provider pointer when `source` is `"knowledge"`. */
423
+ ref?: string;
424
+ }
425
+ interface MemoryWriteOptions {
426
+ mode: "propose" | "commit";
427
+ /** The revision the caller last read (rule 17). */
428
+ ifRevision?: string;
429
+ /** The proposal this commit promotes; dropped once the item is written (rule 21). */
430
+ fromProposal?: string;
431
+ /** Section 10: the calling session's scope. Absent: a host call. */
432
+ scope?: MemoryScope;
433
+ /**
434
+ * Rule 32, on a create. `"operator"` (the default) owns the item by the
435
+ * session's operator; `"node"` shares it with every operator of the node.
436
+ */
437
+ owner?: "operator" | "node";
438
+ }
439
+ interface MemorySearchOptions {
440
+ filter?: MemoryFilter;
441
+ limit?: number;
442
+ }
443
+ interface MemoryStore {
444
+ write(item: MemoryDocument, opts: MemoryWriteOptions): Promise<MemoryRecord>;
445
+ read(id: string, opts?: {
446
+ scope?: MemoryScope;
447
+ }): Promise<MemoryRecord | null>;
448
+ list(filter?: MemoryFilter): Promise<readonly MemoryRecord[]>;
449
+ search(query: string, opts?: MemorySearchOptions): Promise<readonly MemorySearchHit[]>;
450
+ supersede(oldId: string, next: MemoryDocument, opts?: {
451
+ ifRevision?: string;
452
+ scope?: MemoryScope;
453
+ }): Promise<{
454
+ old: MemoryRecord;
455
+ next: MemoryRecord;
456
+ }>;
457
+ archive(id: string, opts?: {
458
+ ifRevision?: string;
459
+ scope?: MemoryScope;
460
+ }): Promise<MemoryRecord>;
461
+ dismiss(proposalId: string, opts?: {
462
+ scope?: MemoryScope;
463
+ }): Promise<void>;
464
+ }
465
+ /** The section 8 port under the `I*` name its knowledge sibling uses. */
466
+ type IMemoryStore = MemoryStore;
467
+ type MemoryStoreErrorCode = "conflict" | "not-found" | "invalid-transition" | "slug-taken";
468
+ /**
469
+ * Base of the store's typed failures. An invalid document is rejected
470
+ * with the document package's `MemoryValidationError` instead, which
471
+ * names the field (rule 13).
472
+ */
473
+ declare class MemoryStoreError extends Error {
474
+ readonly code: MemoryStoreErrorCode;
475
+ constructor(code: MemoryStoreErrorCode, message: string);
476
+ }
477
+ /** Rule 17: `ifRevision` missing or stale on a write that needs it. */
478
+ declare class MemoryConflictError extends MemoryStoreError {
479
+ readonly id: string;
480
+ /** The revision the caller sent, if any. */
481
+ readonly expected: string | undefined;
482
+ /** The revision on disk, `undefined` when the item does not exist. */
483
+ readonly actual: string | undefined;
484
+ constructor(id: string, expected: string | undefined, actual: string | undefined);
485
+ }
486
+ /** No item (or proposal) with that id. */
487
+ declare class MemoryNotFoundError extends MemoryStoreError {
488
+ readonly id: string;
489
+ readonly what: "item" | "proposal";
490
+ constructor(what: "item" | "proposal", id: string);
491
+ }
492
+ /** Rules 7 and 15: a status move the store does not allow. */
493
+ declare class MemoryTransitionError extends MemoryStoreError {
494
+ readonly id: string;
495
+ readonly from: MemoryStatus;
496
+ readonly to: MemoryStatus;
497
+ constructor(id: string, from: MemoryStatus, to: MemoryStatus, detail?: string);
498
+ }
499
+ /** Rule 14: another active item already holds the slug. */
500
+ declare class MemorySlugTakenError extends MemoryStoreError {
501
+ readonly slug: string;
502
+ /** The active item holding it. */
503
+ readonly holder: string;
504
+ constructor(slug: string, holder: string);
505
+ }
506
+
507
+ type Tagged = Pick<MemoryFrontmatter, "tags">;
508
+ /** `node:<id>`, `id` being the AIP-34 id of a node (`@<owner>/<slug>`). */
509
+ declare function nodeTag(id: string): string;
510
+ /** `operator:<id>`, `id` being the body of an AIP-54 `operator:` ref. */
511
+ declare function operatorTag(id: string): string;
512
+ /** The ids of the item's node anchors (an item carries at most one). */
513
+ declare function nodeAnchorIds(item: Tagged): string[];
514
+ /** The ids of the item's operator anchors (an item carries at most one). */
515
+ declare function operatorAnchorIds(item: Tagged): string[];
516
+ /** Whether a tag is a node or operator anchor (neither counts as an anchor for section 9). */
517
+ declare function isNodeOrOperatorTag(tag: string): boolean;
518
+ interface NodeProjectionOptions {
519
+ /**
520
+ * Operator anchor ids the store's AIP-38 read grants let the session
521
+ * read (condition 4). A grant never extends condition 2.
522
+ */
523
+ grantedOperators?: Iterable<string>;
524
+ }
525
+ /**
526
+ * Conditions 2 and 4 of the node projection (section 10), the two that
527
+ * read an item's node and operator anchors. Conditions 1 (in force) and 3
528
+ * (the session's flat anchors) stay with the caller, which has the clock
529
+ * and the anchors; the conditions are an intersection.
530
+ *
531
+ * - With a node scope the item must carry a node anchor, and every node
532
+ * anchor it carries must be in `scope.nodes`; an item with none is out.
533
+ * - Without one, an item with a node anchor is out and one with none is
534
+ * judged by the other conditions alone.
535
+ * - An operator anchor needs the session to run that operator, or a grant.
536
+ */
537
+ declare function isInNodeProjection(item: Tagged, scope: MemoryScope, opts?: NodeProjectionOptions): boolean;
538
+ interface WriteScopeOptions {
539
+ /** Rule 32. Default `"operator"`; `"node"` adds no operator anchor. */
540
+ owner?: "operator" | "node";
541
+ /**
542
+ * The item this write replaces or supersedes. A document that names no
543
+ * node anchor keeps the basis's, and a document that names no owner keeps
544
+ * the basis's kind of ownership, so an edit never moves or hands over an
545
+ * item by default (rule 34: nothing promotes an item by itself).
546
+ */
547
+ basis?: Tagged;
548
+ /** Rule 33: the host declares trees, so a document with no node anchor is refused. */
549
+ declaresTrees?: boolean;
550
+ }
551
+ /**
552
+ * The document a write stores: the node and operator anchors added by
553
+ * default (rules 31 to 33), or a validation error naming `tags`. `scope`
554
+ * absent is a host call (rule 30): nothing is added or confined, but a
555
+ * store whose host declares trees still refuses a document with no node
556
+ * anchor (rule 33).
557
+ */
558
+ declare function applyWriteScope(item: MemoryDocument, scope: MemoryScope | undefined, opts?: WriteScopeOptions): MemoryDocument;
559
+ /**
560
+ * Rule 34. A commit that moves an item to another node changes that anchor
561
+ * and nothing else: not the operator anchor, not the other anchors. (That
562
+ * the new node is in `scope.nodes` is `applyWriteScope`'s check; a node above
563
+ * a sealed or hard wall never is, the projection being cut there.)
564
+ */
565
+ declare function assertRetagOnly(before: Tagged, after: Tagged): void;
566
+
567
+ /**
568
+ * One hit of a knowledge provider, as much of the AIP-10
569
+ * `KnowledgeHit` as the store reads.
570
+ */
571
+ interface MemoryKnowledgeHit {
572
+ readonly sourceId: string;
573
+ readonly chunkId?: string;
574
+ readonly text: string;
575
+ readonly score: number;
576
+ /** `memoryId` (string) names the memory item the hit was indexed from. */
577
+ readonly metadata?: Readonly<Record<string, unknown>>;
578
+ }
579
+ /**
580
+ * The slice of an AIP-10 `IKnowledgeProvider` (`@agentproto/knowledge-engine`)
581
+ * the store delegates search to. Declared structurally so this package
582
+ * takes no dependency on the knowledge engine: any `IKnowledgeProvider`
583
+ * fits as is.
584
+ */
585
+ interface MemoryKnowledgeProvider {
586
+ query(q: {
587
+ readonly query: string;
588
+ readonly topK?: number;
589
+ }): Promise<{
590
+ readonly hits: readonly MemoryKnowledgeHit[];
591
+ }>;
592
+ }
593
+ interface FilesMemoryStoreOptions {
594
+ /** The store directory: `items/<type>/<id>.md` and `proposals/<id>.md` below it. */
595
+ root: string;
596
+ /**
597
+ * Optional search delegate. Its hits are merged with the built-in
598
+ * keyword match: a hit naming an item of this store is checked against
599
+ * the files (rule 22), anything else comes back as `source: "knowledge"`.
600
+ */
601
+ knowledge?: MemoryKnowledgeProvider;
602
+ /** The store's clock: `updated_at` on commits, and the in-force check. */
603
+ now?: () => Date;
604
+ /**
605
+ * The host declares AIP-34 trees (section 10, rule 33): a host call that
606
+ * creates an item or a proposal with no node anchor is refused. Off: the
607
+ * store behaves as sections 8 and 9 alone.
608
+ */
609
+ declaresTrees?: boolean;
610
+ }
611
+ /**
612
+ * AIP-72 section 8 reference store over a directory:
613
+ *
614
+ * ```
615
+ * <root>/items/<type>/<id>.md one memory/v1 item per file
616
+ * <root>/proposals/<sha256>.md pending proposals, not items
617
+ * ```
618
+ *
619
+ * The files are the source of truth and the store keeps no index.
620
+ * `revision` is the SHA-256 (hex) of the file bytes, a proposal id the
621
+ * SHA-256 of the rendered proposal. Files are written to a temp file
622
+ * then renamed into place. Item files are never deleted: a type change
623
+ * renames the file, supersede and archive rewrite the `status` line
624
+ * only. Mutations through one instance are serialized, so a
625
+ * compare-and-set cannot interleave with another write of the same
626
+ * store object; several processes writing one directory are not
627
+ * coordinated.
628
+ */
629
+ declare class FilesMemoryStore implements MemoryStore {
630
+ #private;
631
+ constructor(options: FilesMemoryStoreOptions);
632
+ write(item: MemoryDocument, opts: MemoryWriteOptions): Promise<MemoryRecord>;
633
+ read(id: string, opts?: {
634
+ scope?: MemoryScope;
635
+ }): Promise<MemoryRecord | null>;
636
+ list(filter?: MemoryFilter): Promise<readonly MemoryRecord[]>;
637
+ search(query: string, opts?: MemorySearchOptions): Promise<readonly MemorySearchHit[]>;
638
+ supersede(oldId: string, next: MemoryDocument, opts?: {
639
+ ifRevision?: string;
640
+ scope?: MemoryScope;
641
+ }): Promise<{
642
+ old: MemoryRecord;
643
+ next: MemoryRecord;
644
+ }>;
645
+ archive(id: string, opts?: {
646
+ ifRevision?: string;
647
+ scope?: MemoryScope;
648
+ }): Promise<MemoryRecord>;
649
+ dismiss(proposalId: string, opts?: {
650
+ scope?: MemoryScope;
651
+ }): Promise<void>;
652
+ }
653
+
348
654
  /**
349
655
  * @agentproto/memory: AIP-72 memory/v1 reference implementation.
350
656
  *
@@ -358,8 +664,15 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
358
664
  * - TS: `defineMemory({...})` -> frozen `MemoryHandle` (writer, canonical)
359
665
  * - MD: `parseMemory(src)` -> `MemoryDocument`, then `validateMemory(doc)`
360
666
  * - out: `renderMemory(doc)` -> MEMORY.md text
667
+ *
668
+ * Store (section 8): the `MemoryStore` port and `FilesMemoryStore`, the
669
+ * reference layout (`items/<type>/<id>.md`, `proposals/<id>.md`).
670
+ *
671
+ * Node scope (section 10): `MemoryScope`, the `node:` and `operator:`
672
+ * anchors, and the projection and write rules over a scope the host
673
+ * computed (`isInNodeProjection`, `applyWriteScope`).
361
674
  */
362
675
  declare const SPEC_NAME: "memory/v1";
363
676
  declare const SPEC_VERSION: "1.0.0-alpha";
364
677
 
365
- export { MEMORY_STATUSES, MEMORY_TYPES, type MemoryAnchor, type MemoryCapture, type MemoryDecidedBy, type MemoryDefinition, type MemoryDocument, type MemoryEvidence, type MemoryFrontmatter, type MemoryHandle, type MemoryIssue, type MemoryLifetime, MemoryParseError, type MemoryProvenance, type MemoryStatus, type MemoryType, MemoryValidationError, type MemoryValidationResult, SPEC_NAME, SPEC_VERSION, type ValidateMemoryOptions, defineMemory, isAllowedStatusTransition, isInForce, memoryFrontmatterSchema, memoryStatus, parseMemory, renderMemory, validateMemory };
678
+ export { FilesMemoryStore, type FilesMemoryStoreOptions, type IMemoryStore, MEMORY_STATUSES, MEMORY_TYPES, type MemoryAnchor, type MemoryCapture, MemoryConflictError, type MemoryDecidedBy, type MemoryDefinition, type MemoryDocument, type MemoryEvidence, type MemoryFilter, type MemoryFrontmatter, type MemoryHandle, type MemoryIssue, type MemoryKnowledgeHit, type MemoryKnowledgeProvider, type MemoryLifetime, MemoryNotFoundError, MemoryParseError, type MemoryProvenance, type MemoryRecord, type MemoryScope, type MemorySearchHit, type MemorySearchOptions, MemorySlugTakenError, type MemoryStatus, type MemoryStore, MemoryStoreError, type MemoryStoreErrorCode, MemoryTransitionError, type MemoryType, MemoryValidationError, type MemoryValidationResult, type MemoryWriteOptions, type NodeProjectionOptions, SPEC_NAME, SPEC_VERSION, type ValidateMemoryOptions, type WriteScopeOptions, applyWriteScope, assertRetagOnly, defineMemory, isAllowedStatusTransition, isInForce, isInNodeProjection, isNodeOrOperatorTag, memoryFrontmatterSchema, memoryStatus, nodeAnchorIds, nodeTag, operatorAnchorIds, operatorTag, parseMemory, renderMemory, validateMemory };