Skip to content
Back to skills

Curator

ASecurity

Use when ingesting memory into the wiki, running wiki_curator.py (run/report/validate/lint/search), or linting wiki structure.

  • 89 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 26, 2026
ai-agentspythongobashsqlgitapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 2, 2026

npx -y skills add moonlight-lupin/agent-skills --skill curator --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Curator?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Curator
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/moonlight-lupin-curator/badge)](https://www.skillsdirectory.com/skills/moonlight-lupin-curator)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: curator
description: "Use when ingesting memory into the wiki, running wiki_curator.py (run/report/validate/lint/search), or linting wiki structure."
license: MIT
metadata:
  version: 0.2.0
  author: moonlight-lupin
  platforms: [linux, macos, windows]
  tags: [wiki, curator, knowledge-base, okf]
  hermes:
    category: research
    related_skills: [obsidian, arxiv]
---

# Wiki Curator

## Overview

The curator is the operational half of Lumen. It turns memory-source records into conservative Markdown wiki updates, and it lints the wiki for structural decay. It never calls providers, never deletes pages, and never overwrites operator-confirmed facts.

Pair it with `lumen:wiki` for methodology (OKF frontmatter, ingest/query/lint procedures). This skill is the CLI and adapter layer.

## When to Use

Use this skill when the user wants to:

- Ingest recent memory into the wiki (`run`) or preview that ingest (`report`)
- Lint or validate wiki structure
- Search wiki pages by keyword, alias, or tag
- Configure which memory source the curator reads

## Wiki Location

Resolve the wiki path in this order:

1. `--wiki` CLI override
2. `paths.wiki_path` in plugin config (`shared/config/lumen.yaml` or `--config`)
3. `$WIKI_PATH` environment variable
4. Default `~/wiki`

## Plugin config (`lumen.yaml`)

Default file: `<plugin>/shared/config/lumen.yaml`. Override with `--config` or `LUMEN_CONFIG`.

```yaml
paths:
  wiki_path: ~/wiki          # null → $WIKI_PATH → ~/wiki

curator:
  timezone: Asia/Singapore
  max_write_pages: 20        # 0 or negative disables the cap
  memory_source: sessions    # sessions | auto | json-file | mnemosyne | none
```

`auto` prefers `sessions` when a readable Hermes `state.db` exists (the conversation history is the ground truth; Mnemosyne holds derived notes), then Mnemosyne when `hermes` is on `PATH`, falling back to the json-file adapter if the export fails. `none` disables ingest (file-only lint/search still work).

## Adapter layer

`${HERMES_SKILL_DIR}/scripts/adapters.py` is the read-only memory boundary. Adapters emit `SourceItem` records (`source_id`, `source_kind`, `title`, `text`, `timestamp`, `tags`, `people`, `entities`, `projects`, `raw`). Nothing writes back to a memory store.

| Adapter | Source | Notes |
|---|---|---|
| `sessions` | Hermes `state.db` (conversation history) | Read-only SQLite; user messages paired with the first assistant reply; gateway-origin JSON envelopes stripped. Default source. |
| `json-file` | `<wiki>/.knowledge/memory.json` | Tolerant record shapes (`records` map or list). Missing file → `[]`. |
| `mnemosyne` | `hermes mnemosyne export --output <tmp>` | Parses `working_memory` + `episodic_memory`. Subprocess failure → `[]`. |
| `none` | empty | Explicit opt-out. |

**Record fields.** `people` / `entities` / `projects` take a list for several names; a plain string is one name (`"Acme, Inc."` stays one entity). `tags` may be a list or a comma-separated string. Records without an `id` get a content-derived id (`memory_<digest>` of timestamp and text), so reordering or inserting records does not re-ingest them. When a record names no people/entities/projects, capitalised words in its title/text are used as entity hints; a sentence-initial word ("Met with…", "Sent…") only counts if the same word also appears capitalised mid-sentence, and the `Untitled` placeholder title is never scanned.

**Extension point (`generic-json`).** Any provider that can emit the json-file `memory.json` shape (a `records` mapping or a list of record objects, with tolerant people/entities/projects keys) can be dropped in as `<wiki>/.knowledge/memory.json` and selected with `memory_source: json-file`. A dedicated `generic-json` adapter that takes an arbitrary export path is the documented next step; do not add provider-specific imports.

## CLI

Script: `${HERMES_SKILL_DIR}/scripts/wiki_curator.py` (Hermes substitutes `${HERMES_SKILL_DIR}` with this skill's directory, so the path works from any cwd). Run with system `python3` (stdlib + PyYAML).

```bash
CURATOR="${HERMES_SKILL_DIR}/scripts/wiki_curator.py"

python3 "$CURATOR" run --since 24h          # ingest (writes wiki pages)
python3 "$CURATOR" run --since 24h --dry-run
python3 "$CURATOR" report --since 7d        # planned changes, no writes
python3 "$CURATOR" validate                 # lint; exit 1 on ERROR
python3 "$CURATOR" lint                     # same checks
python3 "$CURATOR" lint --summary           # counts only
python3 "$CURATOR" search "Acme" --format json --limit 10
python3 "$CURATOR" search "Acme" --format text --wiki ~/wiki
```

Global flags: `--config <lumen.yaml>`, `--wiki <path>` (also accepted after the subcommand).

`--since` accepts `90m`, `24h`, `7d`, `2w`; anything else is a usage error (exit 2). Runtime errors such as a wiki subdirectory that is a symlink out of the wiki print `error: …` and exit non-zero.

**Read-only vs mutating:** `lint`, `validate`, `report`, and `search` are read-only. `run` writes. `run --dry-run` previews. The curator never deletes pages.

## Conservative write policy

- Create or update people / project / entity / daily pages from source items only
- Preserve operator-confirmed facts; append observations with `[source: id]`
- Refresh only the `<!-- lumen:auto:start -->` … `<!-- lumen:auto:end -->` block of `index.md` and `overview.md` (hand-written content outside the markers is preserved; a file without markers gets a block appended); append `log.md`
- Record text, titles and names are flattened to one line with `[source:` / `[[` / leading `#` neutralised, so memory content cannot forge sections, source markers or links
- Never overwrite an existing page `title` or `created` value
- Skip an existing page whose YAML frontmatter does not parse: it is left byte-for-byte unchanged, a `skip` line naming the page appears in the run report (and a warning on stderr), and the source is retried on the next run once the page is fixed
- Rewritten files keep their existing permission bits; new files get `0666 & ~umask`
- Cap source items per run at `curator.max_write_pages` (default 20; 0 or negative disables the cap)
- Backup the wiki tree to `<wiki>/.lumen/backup/<timestamp>/` before large batches (>5 items). `.lumen/` is excluded from index and overview regeneration.

## OKF v0.2

Every curated `.md` page needs parseable YAML frontmatter with a non-empty `type` field. See `lumen:wiki` for the full schema. The curator assigns `seq` on create and preserves `aliases` / `relations`.

## Lint checks

- Missing or malformed frontmatter (ERROR)
- Missing `type` (ERROR)
- Broken `[[wikilinks]]` (WARN)
- Duplicate titles (WARN)
- Pages absent from `index.md` (WARN)
- Orphans with no inbound links (INFO)
- Stale pages (updated >90 days) (INFO)

## File naming

Lowercase hyphenated ASCII slugs: `acme-logistics.md`. Accents are folded (`Zoë` → `zoe.md`); a name with no ASCII letters or digits (`张伟`) gets `untitled-<first 8 hex of sha256(name)>.md`, stable across runs and distinct per name. Wikilinks use the page title, so `[[张伟]]` resolves. Avoid generic names like `notes.md`.

## Common pitfalls

1. Skipping orientation (`purpose.md`, `SCHEMA.md`, `index.md`, recent `log.md`)
2. Creating duplicate entity pages without searching first
3. Dumping raw notes as curated knowledge
4. No frontmatter / missing `type`
5. Unlinked pages that lint later reports as orphans

## Verification checklist

- [ ] Wiki path resolved from plugin config, then `$WIKI_PATH`, then `~/wiki`
- [ ] `memory_source` matches the host install (`auto` / `json-file` / `mnemosyne` / `none`)
- [ ] `run --dry-run` reviewed before a mutating `run`
- [ ] Lint reports file paths and severity
- [ ] Query answers cite wiki pages

Files in this skill

  • SKILL.md5.4 KB
  • scripts/adapters.py16.9 KB
  • scripts/config_loader.py8.7 KB
  • scripts/wiki_curator.py71.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.