mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-09-22 00:32:49 +00:00
docs(protocol): add typed edge link protocol documentation Add comprehensive documentation for the link protocol supporting typed edges in body text. This includes specification for three legal inline forms (bare wikilink, line-level Dataview, inline-bracketed Dataview), predicate syntax rules, and the machine-managed Relations section convention for organizing discovered edges. fix(memory): update path reference from vault_root to working_dir Change the memory_create operation's path anchoring from vault_root to working_dir to maintain consistency with the current working directory configuration. refactor(components): remove edge_extractor module and simplify parsing Remove the edge_extractor component module entirely and inline edge extraction logic directly into LinkedFileParser using parse_wikilinks utility. This simplifies the architecture by eliminating the separate edge extraction component and delegating edge discovery to the maintainer's enrichment operations. feat(parser): update parse method signature and simplify edge extraction Modify LinkedFileParser to return (FileNode, list[FileChunk]) tuple instead of ParsedFile, remove dependency on BaseEdgeExtractor, and implement direct wikilink parsing from body text only. ```
191 lines
8.2 KiB
Markdown
191 lines
8.2 KiB
Markdown
# Memory Protocol
|
|
|
|
Single source of truth for vault schema, conventions, and the R-M-W
|
|
write loop. Consumed by:
|
|
|
|
- **Ingestor's embedded ReAct prompt** (`reme2/memory/ingestor.yaml` —
|
|
injected as `{protocol}` at load time).
|
|
- **Strong-agent SKILL** (`reme-plugin/skills/reme/SKILL.md` —
|
|
transcluded so the host agent sees the same rules).
|
|
|
|
Anything that defines schema invariants, path templates, write tool
|
|
semantics, or the R-M-W decision tree belongs here. Anything role-
|
|
specific (caller framing, audit trail expectations, summary
|
|
requirements) stays in the consumer.
|
|
|
|
## Vault layout
|
|
|
|
- **Topics** — long-lived cognitive memory at `topics/{folder}/{name}.md`.
|
|
A **folder topic** has `folder == name`; it's the cluster's index head.
|
|
Short wikilink `[[X]]` resolves to the folder topic if one exists,
|
|
else falls back to a unique same-stem file.
|
|
- **Events** — fact log of one session at
|
|
`events/{YYYY-MM-DD}/{name}/{name}.md`. The `.md` is the **index**
|
|
inside a folder; sibling files are **materials** (raw conversation,
|
|
tool outputs, data dumps). The index lists them under `## Materials`.
|
|
|
|
## Frontmatter — 4 schema axes
|
|
|
|
Every memory declares 4 orthogonal axes. The legacy `category` field is
|
|
auto-translated to these axes for back-compat reads, but new writes
|
|
should set the axes directly.
|
|
|
|
| Axis | Values | Meaning |
|
|
|---|---|---|
|
|
| `lifecycle` | `streaming` / `evolving` / `frozen` | streaming = events (decay/archive); evolving = topics (long-lived, edited); frozen = materials (immutable references) |
|
|
| `scope` | `instance` / `class` | instance = a specific moment / object; class = abstract concept / role / pattern |
|
|
| `source` | `auto` / `curated` / `derived` | auto = system-captured; curated = human/LLM intent; derived = computed from other memories |
|
|
| `role` | `observation` / `claim` / `question` / `profile` / `concept` / `method` / `reference` / `fundamentals` | cognitive role — drives ranking + role-specific validation |
|
|
|
|
### Conditional fields
|
|
|
|
- `confidence` ∈ {⏳, ✅, ❌} — **REQUIRED** when `role: claim` (legacy
|
|
categories `thesis` / `model`). Same gate applies to `role: question`
|
|
(legacy `questions`).
|
|
- `status` ∈ {`active`, `distilled`, `archived`} — meaningful only for
|
|
`lifecycle: streaming`. Topic-style memories ignore it.
|
|
- `originSessionId` — should be set when `source: auto`.
|
|
|
|
### Standard identity fields
|
|
|
|
`title`, `description`, `tags`, `created`, `updated`, `topics`,
|
|
`parent`. Use today's date for `created` / `updated` on new writes.
|
|
|
|
## Cross-file references
|
|
|
|
`[[wikilink]]` syntax. Two forms:
|
|
|
|
- **Stem form** `[[X]]` — resolved against the file_store's stem index;
|
|
prefers the folder topic if one exists.
|
|
- **Path form** `[[topics/X/X]]` or `[[topics/X/X.md]]` — anchored at
|
|
the vault root.
|
|
|
|
## Link protocol — typed edges in body text
|
|
|
|
Edges live **only in body text**. YAML frontmatter is not walked for
|
|
links; a `links:` block in frontmatter is silently ignored by the
|
|
parser. Three legal inline forms:
|
|
|
|
| Form | Example | Predicate |
|
|
|---|---|---|
|
|
| Bare wikilink | `[[X]]` | `None` |
|
|
| Line-level Dataview | `extends:: [[X]]` | `extends` |
|
|
| Inline-bracketed Dataview | `[extends:: [[X]]]` | `extends` |
|
|
|
|
Multi-target on one field expands to multiple edges:
|
|
|
|
concerns:: [[Topic A]], [[Topic B]]
|
|
|
|
Bullet markers are tolerated (`- extends:: [[X]]`, `* extends:: [[X]]`).
|
|
|
|
### Predicate syntax
|
|
|
|
A predicate is any **identifier-shaped token**: starts with a letter,
|
|
followed by letters / digits / underscore (regex
|
|
`[A-Za-z][A-Za-z0-9_]*`). The parser preserves whatever it sees — no
|
|
closed vocabulary at the schema layer. Choose predicates that read
|
|
well in prose (`extends`, `contradicts`, `derives_from`, `concerns`,
|
|
`supersedes`, …); the maintainer's lint pass can later surface
|
|
inconsistencies if a vocabulary policy is desired.
|
|
|
|
### `## Relations` section (machine-managed)
|
|
|
|
The maintainer's `discover` op appends newly discovered edges as
|
|
Dataview line-level fields under a `## Relations` heading at the end
|
|
of the file (creating the heading if absent). Example:
|
|
|
|
## Relations
|
|
|
|
extends:: [[Source Topic]]
|
|
concerns:: [[Topic A]]
|
|
|
|
`## Relations` is a **convention**, not a protocol — the parser treats
|
|
edges anywhere in the body uniformly. The heading is just the default
|
|
write location so machine-added edges stay separate from prose for
|
|
human review.
|
|
|
|
## Status state machine
|
|
|
|
`active → distilled → archived` (single direction, no skip). A reverse
|
|
or skip transition will be flagged by the Maintainer.
|
|
|
|
## Wikilink uniqueness
|
|
|
|
Every create path routes through `MemoryCreate.write`, which refuses to
|
|
introduce ambiguity (existing `[[X]]` would resolve to ≥2 paths). When
|
|
rejected, the response includes a `suggested_name`. Retry with that, or
|
|
pick a domain-specific qualifier (`Apple-Inc` beats `Apple-2`). Never
|
|
bypass with `force=true` unless you fully understand the ambiguity.
|
|
|
|
## Available tools
|
|
|
|
### Read tools (gather context BEFORE writing)
|
|
|
|
- `memory_get(path, include_chunks=False)` — full file content +
|
|
frontmatter. On an event index, follow `## Materials` and read each
|
|
artifact whose content you need.
|
|
- `memory_list(path_prefix=None, tags=None, metadata=None, limit=100)`
|
|
— list indexed files filtered by prefix / tags / frontmatter.
|
|
- `memory_resolve_wikilink(wikilink)` — resolve `[[X]]` to a path;
|
|
flags ambiguity / dangling.
|
|
- `memory_backlinks(path)` — files linking TO the given path.
|
|
- `memory_links(path)` — files the given path links to.
|
|
- `memory_search(query, …)` — hybrid (vector + keyword) chunk search.
|
|
- `memory_graph_search(query, seeds, graph_depth, …)` — vector +
|
|
keyword + graph BFS fusion.
|
|
|
|
### Write tools (mutations are SSOT-routed; each returns success +
|
|
payload + records to audit)
|
|
|
|
- `memory_update(path, old_string, new_string, replace_all=False)` —
|
|
body edit by exact-string substitution. Use a tail snippet to append.
|
|
- `memory_property_update(path, key, value)` — change one frontmatter
|
|
key (`value=null` deletes). Use this to flip status.
|
|
- `memory_create(path, metadata, content, overwrite=False, force=False)`
|
|
— new file. Reserve for genuinely NEW topics. Do NOT use for events
|
|
(`sync` owns events). All paths must be ABSOLUTE under working_dir.
|
|
- `memory_rename(old_path, new_path)` — move file + rewrite cross-vault
|
|
wikilinks. Refuses on destination conflict or stem ambiguity.
|
|
- `memory_delete(path)` — remove a file.
|
|
- `memory_archive(path)` — flip `status: archived` and move under
|
|
`<vault>/Archive/`.
|
|
|
|
### Hot-write helper (deterministic, no LLM)
|
|
|
|
- `sync(name, description?, content?, topics?, tags?, materials?,
|
|
on_date?)` — idempotent upsert of an event FOLDER per `(date, name)`.
|
|
Reuse the same `name` across calls in one thread to keep extending
|
|
the same folder. Refuses on `status: distilled` / `archived` and
|
|
returns a `suggested_name`.
|
|
|
|
## R-M-W decision rules
|
|
|
|
Apply in order. Stop at the first match.
|
|
|
|
1. **SKIP** — if material is ALREADY covered by existing topics, reply
|
|
with a single line `SKIP: <one-line reason>` and call no tools.
|
|
2. **CONTRADICT** — if material CONTRADICTS an existing block, use
|
|
`memory_update` with a unique snippet of the outdated text and the
|
|
corrected replacement.
|
|
3. **EXTEND** — if material EXTENDS an existing topic, use
|
|
`memory_update` with a unique TAIL snippet of the existing body, and
|
|
`new_string = tail + blank line + new content`.
|
|
4. **CREATE** — if material warrants a GENUINELY NEW topic, use
|
|
`memory_create` at `topics/{folder}/{name}.md`. Do NOT
|
|
`memory_create` under `events/` — `sync` owns that path.
|
|
5. **STATUS FLIP** — after integrating an event's content into a
|
|
topic, flip that event's status to `distilled` with
|
|
`memory_property_update`.
|
|
|
|
## Operating principles
|
|
|
|
- **Read before write.** Always inspect related topics before deciding
|
|
CONTRADICT vs EXTEND vs CREATE. The wikilink-uniqueness gate refuses
|
|
blind creates; reading first prevents wasted attempts.
|
|
- **Minimal edits.** Edit only what must change. Don't restructure
|
|
while updating content.
|
|
- **Frontmatter on create.** Always include reasonable frontmatter:
|
|
the 4 axes, `title`, `created`, `updated`, plus `confidence` when
|
|
`role: claim` or `role: question`.
|
|
- **Never delete unless asked.** Distillation flips status; it does
|
|
not remove events.
|