ReMe/reme2/config/service.yaml
huangsen 8465f6d06e ```
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.
```
2026-05-11 19:45:53 +08:00

271 lines
11 KiB
YAML

app_name: reme-service
enable_logo: false
log_to_console: true
log_to_file: false
# Service profile: service-aligned MCP surface — three tools, one per
# memory service:
# `retrieve` — graph-aware hybrid retrieval (Retriever projection)
# `remember` — single write entry point (Ingestor projection)
# * mode=log → zero-LLM event-folder upsert
# * mode=distill → LLM R-M-W into topic graph
# `maintain` — vault hygiene sweep (Maintainer projection)
# runs lint + decay; merge/split require an LLM and
# are off by default.
#
# The agent calls `remember(mode=log, name=…, content=…, materials=…)`
# continuously through the task — picking a stable `name` per logical
# thread so each call extends the same event folder rather than
# fragmenting. At task completion (or PreCompact / SessionEnd) it
# calls `remember(mode=distill, content=…, related_paths=…)` once to
# distill the active events into topic-level cognition. `maintain` is
# typically cron-driven, but the agent can invoke it explicitly when
# it suspects vault drift.
#
# For full direct control over every memory_* primitive (raw writes,
# fine-grained reads, separate sync/ingest tools, memory_lint) see
# ./expert.yaml.
service:
backend: mcp
transport: stdio
sidecar_http: true
sidecar_http_host: "127.0.0.1"
sidecar_http_port: 8765
sidecar_info_path: "./vault/.reme/sidecar.json"
jobs:
- backend: base
name: retrieve
description: |
Graph-aware hybrid retrieval: vector + keyword + 1-hop wikilink
BFS fusion. Use for "what do I know about X" / "did I work on Y" /
"what's connected to [[Z]]". Anchor mode: include `[[Target]]` in
the query to seed BFS at that file. Topic-rooted mode: pass `seeds`
explicitly. Returns chunks ranked by combined relevance + graph
proximity, each tagged with `graph_hop`.
parameters:
type: object
properties:
query: { type: string }
max_results: { type: integer, default: 5 }
min_score: { type: number, default: 0.0 }
graph_depth:
type: integer
default: 1
description: "BFS hops from seeds. 1 covers immediate neighbors."
seeds:
type: array
items: { type: string }
description: "Explicit seed paths (topic-rooted mode)."
paths: { type: array, items: { type: string } }
tags: { type: array, items: { type: string } }
exclude_paths: { type: array, items: { type: string } }
steps:
- backend: memory_graph_search
- backend: base
name: remember
description: |
Single write entry point — projects the Ingestor service. Two
modes via the `mode` parameter:
* `mode: log` (zero LLM, hot path) — idempotent upsert of an
event FOLDER under `events/{date}/{name}/`. The folder
contains the index `{name}.md` (Event schema, frontmatter +
narrative + Materials footer) plus any raw materials you
pass — conversation snippets, tool outputs, data dumps. The
watcher indexes everything inside.
CONTINUITY MODEL: pick a stable `name` per logical thread
and call `remember(mode=log, ...)` repeatedly through the
task. Each call extends the same folder:
- new `content` → appended under a `## Update — {iso}`
section
- new `materials` → siblings (auto-suffix on filename
collision)
- `topics` + `tags` merged (union) into frontmatter
- Materials footer regenerated to list every artifact
First call (folder doesn't exist) → CREATE; subsequent calls
with the same `name` while the event is `status: active` →
APPEND. If `status: distilled` / `archived`, REFUSES and
returns `suggested_name` so you start a fresh thread instead
of mutating prior cognition. Call CONTINUOUSLY through a task
as facts land, especially at PreCompact to dump verbose raw
text into `materials` before context truncation.
* `mode: distill` (LLM R-M-W loop, cold path) — DEFAULT. Run
on EXPLICIT HANDOFF only: task completion / SessionEnd / when
you decide the working set is ready. Not a per-turn tool.
Hand off the working set in two interchangeable forms:
- `content` — inline material to distill (hint, summary, or
raw text)
- `related_paths` — pointers (event folder indexes; the
Ingestor follows `## Materials` to read each artifact,
individual material files, candidate topics).
The Ingestor reads the working set + linked topics, decides
which existing topics to update / create, and flips each
distilled event's status to "distilled". Returns an audit
trail.
parameters:
type: object
required: [content]
properties:
mode:
type: string
enum: [log, distill]
default: distill
description: "log = zero-LLM event-folder upsert (requires `name`); distill = LLM R-M-W into topic graph (default)."
# mode=log params
name:
type: string
description: "(mode=log) kebab-case event identifier (folder + index stem). Reuse the same name across calls in one thread to keep extending the same folder."
description:
type: string
description: "(mode=log) one-line summary for index frontmatter (set on initial create only)."
topics:
type: array
items: { type: string }
description: "(mode=log) related topic wikilinks. Unioned into frontmatter on append."
tags:
type: array
items: { type: string }
description: "(mode=log) free-form tags; unioned on append."
materials:
type: array
description: "(mode=log) raw artifacts written as siblings of the index. Filenames must be safe (letters/digits/dot/underscore/dash). Filename collision auto-suffixes (foo.txt → foo-2.txt)."
items:
type: object
required: [filename, content]
properties:
filename: { type: string, description: "e.g. 'raw-prompt.md', 'tool-output.txt'" }
content: { type: string }
on_date:
type: string
description: "(mode=log) ISO date for events/{date}/ bucket; defaults to today."
origin_session_id:
type: string
description: "(mode=log) optional source session identifier (set on initial create only)."
# shared / mode=distill params
content:
type: string
description: "Required. mode=log: markdown body for the index (initial create) or appended `## Update — {iso}` section. mode=distill: inline material the Ingestor distills — hint, summary, or raw text."
hint:
type: string
description: "(mode=distill) caller guidance about target / intent."
target_path:
type: string
description: "(mode=distill) optional suggested path; required for the no-LLM degraded path."
metadata:
type: object
description: "(mode=distill) suggested frontmatter for any new topic."
related_paths:
type: array
items: { type: string }
description: "(mode=distill) pointers — event folder indexes (Ingestor reads materials from `## Materials`), individual material files, or candidate topics."
steps:
- backend: ingestor
- backend: base
name: maintain
description: |
Vault hygiene sweep — projects the Maintainer service. One pass:
scan signals → propose ops → resolve conflicts → apply. Returns
an audit trail of what ran and what changed.
Default behavior runs `lint` (broken wikilinks, schema violations,
stem collisions — read-only diagnostics) and `decay` (move stale
events past their freshness window under `<vault>/Archive/`).
Merge / split require an LLM and are off unless explicitly opted
into via `ops`.
Typically cron-driven; the agent invokes it on demand when it
suspects vault drift (after a heavy session of edits, after a
bulk rename, etc.). Dry-run by default — flip `dry_run=false` to
apply changes.
parameters:
type: object
properties:
target_prefix:
type: string
description: "restrict scan to relpaths starting with this prefix (e.g. 'events/2026-05-09/'). Empty string scans the whole vault."
dry_run:
type: boolean
default: true
description: "if true (default) returns the plan without mutating; flip to false to actually apply lint+decay (and merge/split if opted in)."
ops:
type: array
items:
type: string
enum: [lint, decay, merge, split]
description: "subset of ops to run. Defaults to ['lint','decay']. Merge/split are LLM-driven and currently scaffolded — enabling them without an LLM is a no-op."
decay_days:
type: integer
description: "freshness window for the decay proposer (default = Maintainer constructor `decay_days`, typically 90)."
steps:
- backend: maintainer
components:
# Ingestor LLM (opt-in). Without this the Ingestor degrades to a
# direct create from explicit `target_path`; edits/renames/deletes
# require the LLM. Uncomment + provide LLM_API_KEY to enable.
#
# as_llm:
# default:
# backend: openai
# model_name: ${LLM_MODEL_NAME:-gpt-4o-mini}
# api_key: ${LLM_API_KEY}
# client_kwargs:
# base_url: ${LLM_BASE_URL:-https://api.openai.com/v1}
# stream: false
#
# as_llm_formatter:
# default:
# backend: openai
as_token_counter:
default:
backend: estimated
# Embedding is opt-in: leave embedding_model="" on file_store to run
# keyword-only; uncomment + flip to "default" to enable hybrid search.
#
# embedding_model:
# default:
# backend: openai
# model_name: ${EMBEDDING_MODEL_NAME:-text-embedding-3-small}
# dimensions: 1536
# pass_dimensions: false
# enable_cache: true
# max_batch_size: 10
# max_cache_size: 2000
# max_input_length: 8192
file_parser:
md:
backend: md
default:
backend: text
file_store:
default:
backend: local
embedding_model: ""
store_name: "reme"
db_path: "./vault/.reme"
working_dir: "./vault"
fts_enabled: true
file_watcher:
default:
backend: full
file_store: default
default_parser: md
recursive: true
# Retriever (`hybrid`) is a Step, not a pre-instantiated component —
# the `query` shell builds it on demand. Tune defaults by attaching
# knobs to the `memory_graph_search` step under the `query` job above.