@zilliz/memsearch-opencode 0.3.4 → 0.3.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zilliz/memsearch-opencode",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "memsearch plugin for OpenCode — semantic memory search across sessions",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -0,0 +1,59 @@
1
+ You are distilling reusable skills from {{AGENT_NAME}}'s recent memory journals.
2
+
3
+ Project directory: {{PROJECT_DIR}}
4
+ Input memory directory: {{INPUT_DIR}}
5
+
6
+ A "skill" is procedural memory: a reusable, multi-step procedure for getting a
7
+ recurring task done (how to run the app, how to deploy, how to debug a class of
8
+ error). It is NOT a fact, a decision, or a preference — those belong in
9
+ PROJECT.md and USER.md.
10
+
11
+ You will receive recent memory journal entries and a list of existing skills
12
+ (which you MAY revise). Propose or revise skills only when they clearly earn it.
13
+
14
+ Be conservative. Quality over quantity. Most runs should return an empty list.
15
+
16
+ A NEW workflow qualifies as a candidate ONLY when ALL of these hold:
17
+ - It is a repeatable multi-step procedure, not a one-off action or a fact.
18
+ - It recurs across at least {{MIN_OCCURRENCES}} distinct sessions or days in the
19
+ journals below.
20
+ - It generalizes into a reusable capability. If it is tightly coupled to one
21
+ specific ticket, one specific value, or a one-time condition, do NOT propose it.
22
+ - The recent runs were not immediately corrected, abandoned, or undone (a
23
+ workflow the user kept fighting is not a good skill).
24
+ - It is not already covered by an existing skill.
25
+
26
+ You may also REVISE an existing skill (re-emit it with the SAME name and a
27
+ corrected body) when the recent journals show that procedure has genuinely
28
+ changed — a tool, command, flag, or step is now done differently. Only revise when
29
+ there is clear evidence of change; do not rewrite for style.
30
+
31
+ Rules:
32
+ - Return only a JSON object, with no prose outside JSON.
33
+ - Use {"skills": []} when nothing in the journals qualifies. This is the common case.
34
+ - For each candidate, write a clean, portable SKILL.md body in "body": step-by-step
35
+ instructions an agent can follow. Do not include YAML frontmatter — only the
36
+ markdown body. Keep it concise and concrete.
37
+ - "name" must be a short lowercase slug (letters, digits, dashes), e.g. "run-tests".
38
+ It becomes the skill's command name. Do not reuse an existing skill name.
39
+ - "description" is one line: what the skill does AND when it should trigger.
40
+ Lead with the verbs a user would actually type ("run", "deploy", "debug").
41
+ - "occurrences" is how many distinct sessions/days you saw this workflow.
42
+ - "sources" lists the journal file names the workflow was observed in.
43
+ - Do not copy raw journal text wholesale into the body; abstract it into a procedure.
44
+
45
+ How to write a good skill body (this is what makes the skill usable):
46
+ - Write imperative, numbered steps an agent can follow top to bottom.
47
+ - Be concrete: real commands, file paths, and flags — not vague prose.
48
+ - Keep it focused and short. A skill loads only when triggered, so include just
49
+ what is needed to do this one task well, and push rare detail to the end.
50
+ - State any preconditions, and where useful, when NOT to use the skill.
51
+ - Never bake in secrets, tokens, or one-off values; describe them as placeholders.
52
+ - Make it self-contained: an agent on a clean checkout should be able to follow it.
53
+ - The "description" is the trigger signal — if it does not name the situation and
54
+ the verbs a user would type, the skill will never fire. Spend care on it.
55
+
56
+ JSON examples:
57
+ {"skills":[]}
58
+
59
+ {"skills":[{"name":"run-tests","description":"Run the project's test suite and report failures. Use when asked to run tests, check tests, or verify a change.","body":"## Run the tests\n\n1. ...\n2. ...","occurrences":4,"sources":["2026-06-12.md","2026-06-14.md"],"reason":"Test run procedure recurred across 4 sessions."}]}
@@ -363,7 +363,7 @@ def ensure_memsearch_importable() -> None:
363
363
  def apply_plugin_prompt_defaults(cfg) -> None:
364
364
  plugin_dir = Path(__file__).resolve().parent.parent
365
365
  prompts_dir = plugin_dir / "prompts"
366
- for task in ("project_review", "user_profile"):
366
+ for task in ("project_review", "user_profile", "memory_to_skill"):
367
367
  if getattr(cfg.prompts, task, ""):
368
368
  continue
369
369
  prompt_file = prompts_dir / f"{task}.txt"
@@ -388,7 +388,9 @@ def run_native_provider(ctx, prompt: str) -> str:
388
388
  return run_command(cmd, env=env, cwd=ctx.project_dir, timeout=120)
389
389
 
390
390
  if ctx.platform == "codex":
391
- with tempfile.NamedTemporaryFile(prefix="memsearch-codex-maintenance-", suffix=".txt", delete=False) as output_file:
391
+ with tempfile.NamedTemporaryFile(
392
+ prefix="memsearch-codex-maintenance-", suffix=".txt", delete=False
393
+ ) as output_file:
392
394
  output_path = Path(output_file.name)
393
395
  cmd = [
394
396
  "codex",
@@ -476,6 +478,20 @@ def main() -> int:
476
478
  force=args.force,
477
479
  llm_runner=llm_runner,
478
480
  )
481
+
482
+ # Distill recurring workflows into candidate skills (procedural memory).
483
+ # Same session-end trigger, due-state, and llm_runner as the tasks above;
484
+ # this only ever touches the candidate store, never an agent's skills dir.
485
+ from memsearch.skills import distill as distill_skills
486
+
487
+ skill_result = distill_skills(
488
+ platform=args.platform,
489
+ project_dir=project_dir,
490
+ memsearch_dir=args.memsearch_dir,
491
+ cfg=cfg,
492
+ force=args.force,
493
+ llm_runner=llm_runner,
494
+ )
479
495
  except (KeyError, RuntimeError, ValueError, subprocess.SubprocessError) as exc:
480
496
  sys.stderr.write(f"Maintenance error: {exc}\n")
481
497
  return 1
@@ -484,12 +500,15 @@ def main() -> int:
484
500
  os.chdir(old_cwd)
485
501
 
486
502
  payload = [result.__dict__ for result in results]
503
+ payload.append({"task": "memory_to_skill", **skill_result.__dict__})
487
504
  if args.json_output:
488
505
  sys.stdout.write(json.dumps(payload, indent=2, ensure_ascii=False) + "\n")
489
506
  else:
490
507
  for result in results:
491
508
  detail = f": {result.reason}" if result.reason else ""
492
509
  sys.stdout.write(f"{result.task}: {result.action}{detail}\n")
510
+ skill_detail = f": {skill_result.reason}" if skill_result.reason else ""
511
+ sys.stdout.write(f"memory_to_skill: {skill_result.action}{skill_detail}\n")
493
512
  return 0
494
513
 
495
514
 
@@ -19,6 +19,7 @@ When this skill is triggered, inspect the user's request text. If there is no co
19
19
  - "Not capturing/search empty/no memory": troubleshoot files, config, and index health.
20
20
  - "Use OpenAI/Gemini/Anthropic/native/model": configure provider routing.
21
21
  - "PROJECT.md/USER.md/profile/review": configure advanced maintenance.
22
+ - "skill/distill/extract a skill/memory-to-skill": procedural-memory distillation — enable or tune it here, or use the dedicated `/memory-to-skill` skill to review and install candidates.
22
23
  - "Prompt": explain or configure prompt overrides.
23
24
 
24
25
  Ask the user before enabling external or paid providers, changing output paths, re-indexing, deleting state, or broadening what gets indexed.
@@ -145,6 +146,11 @@ model = ""
145
146
  min_interval_hours = 24
146
147
  input_dir = ".memsearch/memory"
147
148
  output_file = ".memsearch/USER.md"
149
+
150
+ [plugins.opencode.memory_to_skill]
151
+ enabled = false
152
+ min_occurrences = 3 # how many times a workflow must recur before it is distilled
153
+ paths = [] # where installed skills are copied; empty = ask the user
148
154
  ```
149
155
 
150
156
  Provider rules:
@@ -192,6 +198,7 @@ Prompt overrides:
192
198
  summarize = ""
193
199
  project_review = ""
194
200
  user_profile = ""
201
+ memory_to_skill = ""
195
202
  ```
196
203
 
197
204
  Empty prompt paths mean use the built-in MemSearch prompts. Custom prompt files may use `{{AGENT_NAME}}`, `{{TASK_NAME}}`, `{{PROJECT_DIR}}`, `{{INPUT_DIR}}`, and `{{OUTPUT_FILE}}`; the runner appends existing output, recent journals, and digest automatically.
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: memory-to-skill
3
+ description: "Turn workflows from your MemSearch memory into reusable skills. Use when the user asks to make/create/extract/distill a skill from what they just did or from past work, review skill candidates, install a distilled skill, or 'turn this into a skill'. Manages MemSearch procedural-memory candidates under .memsearch/skill-candidates/, not OpenCode's own skills system."
4
+ ---
5
+
6
+ You manage MemSearch's **procedural memory**: skills distilled from the work you
7
+ repeat — a third layer beside the daily journals (episodic) and PROJECT.md /
8
+ USER.md (semantic). State once that this is MemSearch skill distillation, not
9
+ OpenCode's built-in skills system.
10
+
11
+ Stages: **0** memory journals → **1** candidate (`.memsearch/skill-candidates/`,
12
+ a git-tracked store that keeps evolving) → **2** installed (an agent skill dir).
13
+ Candidates are never installed automatically; installing is always a human step.
14
+
15
+ ## Intent routing
16
+
17
+ - "make/turn this into a skill", "from what we just did" → **A. Capture now**.
18
+ - "what skills / review candidates / install X" → **B. Review & install**.
19
+ - "mine my history / find recurring workflows" → **C. Distill from history**.
20
+ - "enable / configure / how eager" → **D. Configure**.
21
+ - Unclear or empty → run **B**'s `list`; if empty, offer A or C.
22
+
23
+ ## A. Capture what you just did (0→1→2)
24
+
25
+ You already have the context, so **draft the skill yourself** — do not call the
26
+ background distiller for this. Write a SKILL.md **body** (markdown, no
27
+ frontmatter): imperative numbered steps for the recurring task, concrete commands
28
+ and paths, no secrets, self-contained. Then persist it as a candidate:
29
+
30
+ ```bash
31
+ printf '%s' "## <title>\n\n1. ...\n2. ..." | memsearch skills add \
32
+ --name "<short-slug>" \
33
+ --description "<what it does AND when it should trigger — lead with the verbs a user types>" \
34
+ --body-file -
35
+ ```
36
+
37
+ `add` handles slugging, standard frontmatter, meta.json, and the git commit — no
38
+ LLM is involved. Then show it to the user and install it (see **B**). Finally,
39
+ check whether background distillation is on; if not, offer to enable it (so
40
+ recurring workflows get captured automatically going forward) — do not force it.
41
+
42
+ ## B. Review & install candidates (1→2)
43
+
44
+ ```bash
45
+ memsearch skills list # add -j for sources / installed paths
46
+ ```
47
+
48
+ Pick one, resolve where to install (ask if unset), then install:
49
+
50
+ ```bash
51
+ memsearch config get plugins.opencode.memory_to_skill.paths 2>/dev/null || echo "[]"
52
+ memsearch skills install <name> --path .agents/skills
53
+ ```
54
+
55
+ If the list is **empty**, background distillation is likely off or has not run.
56
+ Offer the user a choice: capture from recent work now (**A**), distill from
57
+ history (**C**), or enable the background pass (**D**).
58
+
59
+ ## C. Mine history for recurring workflows (0→1)
60
+
61
+ To pull skills out of past work (not just the current session), read the recent
62
+ journals yourself — they live in `.memsearch/memory/*.md` — and look for
63
+ multi-step procedures that recur across several sessions. Draft each genuinely
64
+ reusable one and persist it with `memsearch skills add` (one call per skill), the
65
+ same way as **A**. Use your own judgment: only propose procedures that recur and
66
+ generalize, not one-offs from a single day.
67
+
68
+ The background pass does this automatically when enabled; doing it here on demand
69
+ uses your own reasoning and needs no provider configuration.
70
+
71
+ ## D. Configure
72
+
73
+ ```bash
74
+ memsearch config get plugins.opencode.memory_to_skill.enabled 2>/dev/null || echo "false"
75
+ # enable the background pass (do not enable silently)
76
+ memsearch config set plugins.opencode.memory_to_skill.enabled true --project
77
+ # how eagerly history-mining distils (default 3; lower = more eager)
78
+ memsearch config set plugins.opencode.memory_to_skill.min_occurrences 3 --project
79
+ # pre-set install targets (otherwise you are asked at install time)
80
+ memsearch config set plugins.opencode.memory_to_skill.paths '[".agents/skills"]' --project
81
+ ```
82
+
83
+ Note: `enabled` only gates the **background** (session-end) pass. The explicit
84
+ commands above (`skills add`, `skills install`) always work, and you can mine history (C) directly.
85
+
86
+ ## Install paths
87
+
88
+ - `.agents/skills` — **project-local (recommended)**: a skill from this project's
89
+ memory is usually most relevant here.
90
+ - `~/.agents/skills` — global: available across all your projects.
91
+ - a custom path, or several (one skill can be installed to multiple dirs).
92
+
93
+ Each agent reads skills from its own directory: Claude Code `.claude/skills/`;
94
+ Codex and OpenCode `.agents/skills/` (the shared standard, also read by Cursor
95
+ etc.); OpenClaw `.openclaw/skills/`. Claude Code does **not** read `.agents/skills/`.
96
+ Install to multiple paths to cover several agents.
97
+
98
+ ## Guardrails
99
+
100
+ - Never enable the feature, change install paths, or install a candidate without
101
+ the user's go-ahead.
102
+ - Do not hand-edit the store; create candidates with `memsearch skills add` and let
103
+ the git-tracked store at `.memsearch/skill-candidates/` keep history.