suemo 0.1.4 → 0.1.7

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
@@ -11,6 +11,8 @@
11
11
 
12
12
  suemo gives AI agents a memory that survives across sessions, models, and runtimes. Write observations from a Telegram bot, query them from OpenCode, consolidate overnight — all agents share one source of truth in SurrealDB.
13
13
 
14
+ Canonical behavioral specification: **[`SPEC.md`](./SPEC.md)**.
15
+
14
16
  ---
15
17
 
16
18
  ## Features
@@ -170,6 +172,40 @@ suemo observe "Bun is significantly faster than Node for CLI tools" \
170
172
  suemo query "which JS runtime is faster"
171
173
  ```
172
174
 
175
+ To inspect ranking/scoring internals:
176
+
177
+ ```sh
178
+ suemo query "which JS runtime is faster" --explain
179
+ suemo query "which JS runtime is faster" --explain --min-score 0.15 --relative-floor 0.75
180
+ ```
181
+
182
+ `--explain` shows per-strategy contributions (vector/BM25/graph), final score, and applied thresholds.
183
+
184
+ ### How query scoring works
185
+
186
+ `suemo query` computes a hybrid score per candidate and then applies score gates.
187
+
188
+ 1. **Per-strategy raw scores**
189
+ - vector: cosine similarity between memory embedding and query embedding
190
+ - bm25: `search::score(1)` from full-text index
191
+ - graph: anchor-weighted relation strength from top vector anchors
192
+
193
+ 2. **Normalization**
194
+ - `vector_norm = clamp((cosine - 0.2) / 0.8, 0, 1)`
195
+ - `bm25_norm = log1p(raw_bm25) / log1p(max_bm25_in_query)`
196
+ - `graph_norm = clamp(raw_graph, 0, 1)`
197
+
198
+ 3. **Final score**
199
+ - `final = 0.5*vector_norm + 0.25*bm25_norm + 0.15*graph_norm + agreement_bonus`
200
+ - `agreement_bonus = 0.05` when a node matches at least two strategies
201
+
202
+ 4. **Default gates (to reduce false positives)**
203
+ - `final >= 0.08` (`--min-score`)
204
+ - `final >= topScore * 0.65` (`--relative-floor`)
205
+ - `max(vector_norm, bm25_norm) >= 0.08` (primary evidence floor)
206
+
207
+ Use `--explain` to inspect all these values per result.
208
+
173
209
  **5. Start the MCP server**
174
210
 
175
211
  ```sh
@@ -189,25 +225,31 @@ suemo serve --dev
189
225
 
190
226
  ## OpenCode setup (only integration target)
191
227
 
192
- Print copy-paste setup snippets:
228
+ Create/update integration files automatically:
193
229
 
194
230
  ```sh
195
231
  suemo init opencode
196
232
  ```
197
233
 
198
- This prints:
234
+ This updates:
235
+
236
+ - `~/.config/opencode/opencode.jsonc` (preferred) or `.json` fallback with `mcp.suemo`
237
+ - `~/.config/opencode/AGENTS.md` with managed `<!-- SUEMO:START --> ... <!-- SUEMO:END -->` block
238
+
239
+ Preview changes without writing files:
199
240
 
200
- - MCP config snippet (`command: suemo`, `args: ["serve", "--stdio", ...]`)
201
- - minimal AGENTS.md guidance snippet
241
+ ```sh
242
+ suemo init opencode --dry-run
243
+ ```
202
244
 
203
- To fetch the latest skill docs directly from your local checkout:
245
+ To fetch latest skill docs directly from your local checkout:
204
246
 
205
247
  ```sh
206
248
  suemo skill
207
249
  suemo skill core-workflow
208
250
  ```
209
251
 
210
- No files are auto-written by this command.
252
+ This command is idempotent and avoids duplicate `mcp.suemo` entries.
211
253
 
212
254
  ---
213
255
 
@@ -405,6 +447,27 @@ This prints your active target (`url`, `namespace`, `database`) and step-by-step
405
447
 
406
448
  Agents never supply temporal fields (`valid_from`, `valid_until`). These are system-managed.
407
449
 
450
+ ### Memory field semantics (quick reference)
451
+
452
+ - `content`: canonical memory payload.
453
+ - `summary`: optional condensed text for compact retrieval/consolidation. It does **not** replace `content`.
454
+ - `source`: optional provenance label (free-form string), e.g. `prompt-capture`, `consolidation:nrem`.
455
+ - `prompt_source`: optional pointer to the prompt memory record that originated a derived memory.
456
+ - `fsrs_next_review`: optional review timestamp; currently set on `recall()` (not on every ingest).
457
+
458
+ ### Episode `memory_ids`
459
+
460
+ `episode.memory_ids` stores memory IDs attached to an open session, used for session reconstruction.
461
+
462
+ If you rarely see it populated, the typical reason is missing `sessionId` on write calls.
463
+ Current behavior: only write paths invoked with `sessionId` append to `memory_ids`.
464
+ `believe` now supports session linkage too:
465
+
466
+ - CLI: `suemo believe "..." --session <sessionId>`
467
+ - MCP: `believe({ content, sessionId, ... })`
468
+
469
+ See `SPEC.md` for full normative semantics and hardening targets.
470
+
408
471
  ### Scope and longevity notes
409
472
 
410
473
  - Default inferred project scope now uses nearest `<projectDir>/suemo.json` with `main.projectDir` defaulting to `.ua`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "suemo",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "Persistent semantic memory for AI agents — backed by SurrealDB.",
5
5
  "author": {
6
6
  "name": "Umar Alfarouk",
@@ -3,13 +3,38 @@ name: suemo
3
3
  description: OpenCode-focused persistent memory workflow for suemo with CLI/MCP parity and versioned references.
4
4
  license: GPL-3.0-only
5
5
  compatibility: opencode
6
- version: 0.1.4
6
+ version: 0.1.7
7
7
  ---
8
8
 
9
9
  # suemo skill
10
10
 
11
11
  Use suemo to persist technical context across sessions with minimal, project-scoped memory.
12
12
 
13
+ ## Strict defaults (v0.1.7)
14
+
15
+ - Always run pre-checks before implementation:
16
+ - `goal_list({ scope })`
17
+ - `query({ input: "recent work on <topic>", scope })`
18
+ - `context({ scope, limit: 20 })`
19
+ - `observe.kind` accepts only: `observation | belief | question | hypothesis | goal`
20
+ - For non-trivial writes, prefer structured content:
21
+ - `**What**`, `**Why**`, `**Where**`, `**Learned**`
22
+ - End meaningful tasks with:
23
+ - `episode_end({ sessionId, summary, goal, discoveries, accomplished, files_changed })`
24
+ - `goal_resolve({ goalId })` when done
25
+ - `query({ input: "most recent observations", scope })`
26
+ - `health()`
27
+
28
+ ## OpenCode plugin support
29
+
30
+ `suemo init opencode` now installs three things:
31
+
32
+ 1. MCP config entry for suemo
33
+ 2. AGENTS.md suemo block
34
+ 3. OpenCode plugin at `~/.config/opencode/plugins/suemo.ts`
35
+
36
+ The plugin injects strict suemo protocol into system prompt and adds compaction checkpoint reminders.
37
+
13
38
  ## Quick use
14
39
 
15
40
  - CLI latest skill: `suemo skill`
@@ -1,17 +1,25 @@
1
1
  ---
2
2
  name: agents-snippet
3
3
  description: AGENTS.md snippet optimized for suemo skill discovery and usage.
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  ---
6
6
 
7
7
  # AGENTS.md snippet
8
8
 
9
9
  ```md
10
- ## suemo-first memory workflow
10
+ ## suemo-first memory workflow (strict)
11
11
 
12
12
  Before significant work:
13
13
 
14
- - query("what do I know about <topic>")
14
+ - suemo_goal_list({ scope: "<active-scope>" })
15
+ - suemo_query({ input: "recent work on <topic>", scope: "<active-scope>" })
16
+ - suemo_context({ scope: "<active-scope>", limit: 20 })
17
+ - suemo_episode_start({ sessionId: "<session-id>" }) for new tasks
18
+
19
+ Schema guardrails:
20
+
21
+ - suemo_observe.kind must be one of: observation | belief | question | hypothesis | goal
22
+ - Never use discovery/architecture/bugfix as kind
15
23
 
16
24
  If you need latest usage docs:
17
25
 
@@ -21,16 +29,19 @@ If you need latest usage docs:
21
29
 
22
30
  During work:
23
31
 
24
- - observe("...") for concrete facts
25
- - believe("...") for conclusions
26
- - goal_set("...") for long tasks
32
+ - suemo_observe({ content: "**What**: ...\n**Why**: ...\n**Where**: ...\n**Learned**: ...", kind: "observation" })
33
+ - suemo_believe("...") for uncertain interpretations
34
+ - suemo_goal_set("...") for long tasks
27
35
 
28
36
  After completion:
29
37
 
30
- - goal_resolve("...") if applicable
31
- - episode_end(sessionId, summary="...")
38
+ - suemo_episode_end({ sessionId, summary, goal, discoveries, accomplished, files_changed })
39
+ - suemo_goal_resolve({ goalId }) if applicable
40
+ - suemo_query({ input: "most recent observations", scope: "<active-scope>" })
41
+ - suemo_health()
32
42
 
33
43
  After compaction/reset:
34
44
 
35
- - context({ scope: "<project-id>", limit: 20 })
45
+ - suemo_session_context_set({ sessionId, summary: "<compacted summary>" })
46
+ - suemo_context({ scope: "<project-id>", limit: 20 })
36
47
  ```
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: cli-reference
3
3
  description: CLI command reference for suemo v0.0.6 including skill access.
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  ---
6
6
 
7
7
  # CLI reference
@@ -14,10 +14,15 @@ Core:
14
14
  - `suemo serve [--stdio|--dev]`
15
15
  - `suemo skill [reference]`
16
16
 
17
+ Aliases (deprecated, still accepted with warning):
18
+
19
+ - `suemo skills` → use `suemo skill`
20
+ - `suemo init surrealdb` → use `suemo init surreal`
21
+
17
22
  Memory:
18
23
 
19
24
  - `suemo observe <content>`
20
- - `suemo believe <content>`
25
+ - `suemo believe <content> [--session <sessionId>]`
21
26
  - `suemo query <input>`
22
27
  - `suemo recall <nodeId>`
23
28
  - `suemo wander`
@@ -1,40 +1,68 @@
1
1
  ---
2
2
  name: core-workflow
3
3
  description: Canonical suemo operating loop for OpenCode agents.
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  ---
6
6
 
7
7
  # Core workflow
8
8
 
9
- 1. Start with memory lookup:
9
+ 1. Start with strict pre-check:
10
10
 
11
11
  ```ts
12
- query('what do I know about <topic>')
12
+ goal_list({ scope: '<project-scope>' })
13
+ query({ input: 'recent work on <topic>', scope: '<project-scope>' })
14
+ context({ scope: '<project-scope>', limit: 20 })
15
+ episode_start({ sessionId: '<session-id>' }) // when beginning new task
13
16
  ```
14
17
 
15
18
  2. During work, persist concrete discoveries:
16
19
 
17
20
  ```ts
18
- observe('...')
19
- believe('...')
21
+ observe({
22
+ content: '**What**: ...\n**Why**: ...\n**Where**: ...\n**Learned**: ...',
23
+ kind: 'observation',
24
+ scope: '<project-scope>',
25
+ })
26
+ believe({ content: '...', scope: '<project-scope>' })
20
27
  ```
21
28
 
22
- 3. For long tasks:
29
+ 3. Kind schema is strict:
23
30
 
24
31
  ```ts
25
- goal_set('...')
32
+ // valid only:
33
+ // observation | belief | question | hypothesis | goal
26
34
  ```
27
35
 
28
- 4. If compaction/reset happened:
36
+ 4. For long tasks:
29
37
 
30
38
  ```ts
39
+ goal_set({ content: '...', scope: '<project-scope>' })
40
+ ```
41
+
42
+ 5. If compaction/reset happened:
43
+
44
+ ```ts
45
+ session_context_set({
46
+ sessionId: '<session-id>',
47
+ summary: '<compacted summary>',
48
+ })
31
49
  context({ scope: '<project-id>', limit: 20 })
32
50
  ```
33
51
 
34
- 5. Close session:
52
+ 6. Close session with structured fields:
35
53
 
36
54
  ```ts
37
- episode_end(sessionId, summary = '...')
55
+ episode_end({
56
+ sessionId: '<session-id>',
57
+ summary: '...',
58
+ goal: '...',
59
+ discoveries: ['...'],
60
+ accomplished: ['...'],
61
+ files_changed: ['path/to/file'],
62
+ })
63
+ goal_resolve({ goalId: '<goal-id>' }) // if completed
64
+ query({ input: 'most recent observations', scope: '<project-scope>' })
65
+ health()
38
66
  ```
39
67
 
40
68
  Prefer project-scoped memory. Let suemo infer scope from nearest `{projectDir}/suemo.json` (recommended `main.projectDir = '.ua'`).
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: manual-test-plan
3
3
  description: Comprehensive manual test matrix for suemo features and commands.
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  ---
6
6
 
7
7
  # Manual test plan
@@ -35,10 +35,11 @@ Expected:
35
35
 
36
36
  1. `episode_start`
37
37
  2. add observations with `sessionId`
38
- 3. `session_context_set`
39
- 4. `context`
40
- 5. `episode_end` with structured fields
41
- 6. verify episode fields persisted
38
+ 3. add belief with `sessionId` (`suemo believe "..." --session <id>` or MCP `believe({ sessionId })`)
39
+ 4. `session_context_set`
40
+ 5. `context`
41
+ 6. `episode_end` with structured fields
42
+ 7. verify episode fields persisted
42
43
 
43
44
  ## E. Goals
44
45
 
@@ -66,7 +67,17 @@ Expected:
66
67
  2. `suemo skill core-workflow`
67
68
  3. MCP `skill({})`, `skill({ reference: "cli-reference" })`
68
69
 
69
- ## I. Output modes
70
+ ## I. OpenCode init + plugin install
71
+
72
+ 1. `suemo init opencode --dry-run`
73
+ 2. `suemo init opencode`
74
+ 3. Verify files:
75
+ - `~/.config/opencode/opencode.jsonc` or `.json` contains `mcp.suemo`
76
+ - `~/.config/opencode/AGENTS.md` has `<!-- SUEMO:START --> ... <!-- SUEMO:END -->`
77
+ - `~/.config/opencode/plugins/suemo.ts` exists
78
+ 4. Validate plugin appears under OpenCode loaded plugins
79
+
80
+ ## J. Output modes
70
81
 
71
82
  Repeat representative commands under:
72
83
 
@@ -1,11 +1,17 @@
1
1
  ---
2
2
  name: mcp-reference
3
3
  description: MCP tool reference for suemo v0.0.6.
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  ---
6
6
 
7
7
  # MCP tools
8
8
 
9
+ Strictness notes (v0.1.7):
10
+
11
+ - `observe.kind` is strict enum: `observation | belief | question | hypothesis | goal`
12
+ - `episode_end` supports optional structured fields: `summary`, `goal`, `discoveries`, `accomplished`, `files_changed`
13
+ - For reliable agent adoption, pair `episode_end` with `goal_resolve` and post-check `query("most recent observations")`
14
+
9
15
  Write/mutate:
10
16
 
11
17
  - `observe`
@@ -42,5 +48,7 @@ Maintenance:
42
48
  Notes:
43
49
 
44
50
  - Optional `scope` defaults to inferred project id.
51
+ - `believe` accepts optional `sessionId` to attach created belief memories to an open episode.
45
52
  - `update` re-embeds when `content` changes.
46
53
  - `episode_end` accepts structured fields (`goal`, `discoveries`, `accomplished`, `files_changed`).
54
+ - `skill` returns inline references; use `skill({ reference: "core-workflow" })` for canonical loop.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: schema-retention-longevity
3
3
  description: Long-term schema and retention design expectations for suemo.
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  ---
6
6
 
7
7
  # Schema + retention longevity
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: sync-local-vps
3
3
  description: Two-way sync manual scenario for local and VPS SurrealDB.
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  ---
6
6
 
7
7
  # Local ↔ VPS sync scenario
package/src/AGENTS.md ADDED
@@ -0,0 +1,130 @@
1
+ **CRITICAL:** This protocol is mandatory. Start each new task with the checklist below. End each completed task with `suemo_episode_end` + `suemo_goal_resolve` (if applicable). Do not skip.
2
+
3
+ ## 1) Pre-Session Checklist (required)
4
+
5
+ Before implementation:
6
+
7
+ - [ ] `suemo_goal_list({ scope: "<active-scope>" })`
8
+ - [ ] `suemo_query({ input: "recent work on <topic>", scope: "<active-scope>" })`
9
+ - [ ] `suemo_context({ scope: "<active-scope>", limit: 20 })`
10
+ - [ ] Resolve abandoned goals if any
11
+ - [ ] `suemo_episode_start({ sessionId: "<session-id>" })` for new tasks
12
+
13
+ Proceed only after all checks pass.
14
+
15
+ ---
16
+
17
+ ## 2) Strict schema rules (required)
18
+
19
+ ### `suemo_observe` kind is strict
20
+
21
+ Valid `kind` values only:
22
+
23
+ - `observation`
24
+ - `belief`
25
+ - `question`
26
+ - `hypothesis`
27
+ - `goal`
28
+
29
+ ### `suemo_episode_end` payload shape
30
+
31
+ Minimum schema requirement: `sessionId`.
32
+
33
+ Required by protocol when finishing meaningful work:
34
+
35
+ - `summary`
36
+ - `goal`
37
+ - `discoveries` (array)
38
+ - `accomplished` (array)
39
+ - `files_changed` (array)
40
+
41
+ Use exact field names above.
42
+
43
+ ---
44
+
45
+ ## 3) During work
46
+
47
+ Persist important information immediately (not only at the end).
48
+
49
+ Use this structure for non-trivial observations:
50
+
51
+ ```md
52
+ **What**: <what changed>
53
+ **Why**: <reason>
54
+ **Where**: <files/paths>
55
+ **Learned**: <gotchas/decisions>
56
+ ```
57
+
58
+ Guidance:
59
+
60
+ - Facts → `suemo_observe`
61
+ - Interpretations/uncertainty → `suemo_believe`
62
+ - Longer tasks → `suemo_goal_set`
63
+
64
+ ---
65
+
66
+ ## 4) After completion
67
+
68
+ Run in order:
69
+
70
+ 1. `suemo_episode_end({ sessionId, summary, goal, discoveries, accomplished, files_changed })`
71
+ 2. `suemo_goal_resolve({ goalId })` when done
72
+ 3. `suemo_query({ input: "most recent observations", scope })`
73
+ 4. `suemo_health()`
74
+
75
+ ---
76
+
77
+ ## 5) Querying best practices
78
+
79
+ Prefer specific, scoped queries:
80
+
81
+ ```ts
82
+ suemo_query({
83
+ input: 'past decisions about auth middleware',
84
+ scope: '<project-id>',
85
+ })
86
+ suemo_query({
87
+ input: '"SURREAL_CAPS_ALLOW_FUNC" init fix',
88
+ scope: '<project-id>',
89
+ })
90
+ ```
91
+
92
+ When weak ranking is suspected, run `--explain` from CLI to inspect scoring.
93
+
94
+ ---
95
+
96
+ ## 6) Anti-patterns
97
+
98
+ - ❌ Storing transient state (cursor position, temporary thoughts)
99
+ - ❌ Storing raw code snippets instead of distilled understanding
100
+ - ❌ Querying on every small step
101
+ - ❌ Skipping `suemo_episode_end`
102
+ - ❌ Forgetting `suemo_goal_resolve`
103
+ - ❌ Using non-schema `kind` values
104
+
105
+ ---
106
+
107
+ ## 7) Compaction/reset handling
108
+
109
+ Immediately:
110
+
111
+ 1. `suemo_session_context_set({ sessionId, summary: "<compacted summary>" })`
112
+ 2. `suemo_context({ scope: "<project-id>", limit: 20 })`
113
+ 3. Continue work
114
+
115
+ ---
116
+
117
+ ## 8) Documentation shortcuts
118
+
119
+ ```bash
120
+ suemo skill
121
+ suemo skill core-workflow
122
+ suemo skill mcp-reference
123
+ suemo skill manual-test-plan
124
+ ```
125
+
126
+ Load docs once per session unless requirements changed.
127
+
128
+ ---
129
+
130
+ _Version: 0.1.7 | Updated: 2026-03-23 | Summary: stricter schema + explicit completion contract_
@@ -12,6 +12,7 @@ export const believeCmd = app.sub('believe')
12
12
  .flags({
13
13
  scope: { type: 'string', short: 's', description: 'Scope label' },
14
14
  confidence: { type: 'number', description: 'Confidence 0.0–1.0', default: 1.0 },
15
+ session: { type: 'string', description: 'Session ID (attach to open episode)' },
15
16
  json: { type: 'boolean', description: 'Output JSON result' },
16
17
  pretty: { type: 'boolean', description: 'Human-readable output (default)' },
17
18
  })
@@ -32,12 +33,14 @@ export const believeCmd = app.sub('believe')
32
33
  hasScope: Boolean(resolvedScope),
33
34
  scope: resolvedScope,
34
35
  confidence: flags.confidence,
36
+ hasSession: Boolean(flags.session),
35
37
  contentLength: args.content.length,
36
38
  })
37
39
  const { node, contradicted } = await believe(db, {
38
40
  content: args.content,
39
41
  scope: resolvedScope,
40
42
  confidence: flags.confidence,
43
+ sessionId: flags.session,
41
44
  }, config)
42
45
  if (outputMode === 'json') {
43
46
  const out: Record<string, unknown> = { id: node.id, valid_from: node.valid_from }