/hns-lsel-curator
Local Self-Evolution Loop (LSEL) curator — the CLUSTER + drain engine for the GOOS-local PROPOSE→APPLY seam closure (SPEC-LSEL-LOCAL-EVOLUTION-001). Companion-offset drain of .moai/lessons-inbox.jsonl with a drain-side severity filter that drops the ~65% Bash-timeout/sandbox
Claude Code
$ npx -y skills add modu-ai/moai-adk --skill hns-lsel-curator --agent claude-code
Codex
$ npx skills add modu-ai/moai-adk --skill hns-lsel-curator -a codex -y
Cursor
$ npx skills add modu-ai/moai-adk --skill hns-lsel-curator -a cursor -y
Gemini CLI
$ npx skills add modu-ai/moai-adk --skill hns-lsel-curator -a gemini-cli -y
GitHub Copilot
$ npx skills add modu-ai/moai-adk --skill hns-lsel-curator -a github-copilot -y
OpenCode
$ npx skills add modu-ai/moai-adk --skill hns-lsel-curator -a opencode -y
Windsurf
$ npx skills add modu-ai/moai-adk --skill hns-lsel-curator -a windsurf -y
SKILL.md
hns-lsel-curator.SKILL.mdname: hns-lsel-curator
description: >
Local Self-Evolution Loop (LSEL) curator — the CLUSTER + drain engine for the
GOOS-local PROPOSE→APPLY seam closure (SPEC-LSEL-LOCAL-EVOLUTION-001). Companion-offset
drain of .moai/lessons-inbox.jsonl with a drain-side severity filter that drops the ~65%
Bash-timeout/sandbox noise, event_key clustering with a frequency gate, and a
Generative-Agents-style 1-10 importance score. Candidates stage at
.moai/state/lsel/clusters.json. M1 = drain only (NO PROPOSE, NO APPLY, NO memory/ writes).
allowed-tools: Read, Grep, Glob, Bash
user-invocable: false
metadata:
version: "0.2.0"
category: "harness"
status: "active"
updated: "2026-08-26"
tags: "lsel,self-evolution,drain,cluster,harness,dogfood"
hns-lsel-curator — LSEL CLUSTER + drain engine
> **Namespace:** `hns-lsel-*` is user-owned dogfood (CLAUDE.local.md §24). This skill is > NOT mirrored into `internal/template/templates/` — it lives only in this repo. Graduation > to `moai-lsel-*` + 16-language distribution is a separate SPEC (out of scope per spec.md §G). > > **M1 scope:** drain + cluster + stage candidates. NO APPROVE, NO APPLY (M3). > **M2 scope:** drain + cluster + **PROPOSE shadow** (no APPROVE, no APPLY). The PROPOSE stage > emits shadow proposals + self-critiques; APPROVE/APPLY land in M3 via the fresh > `hns-lsel-applier` path. M2 does NOT write to `memory/` — the first `feedback_*.md` topic > file is an M3+ deliverable after APPROVE.
What this skill does
The MoAI-ADK repo accumulates failure-event stubs in `.moai/lessons-inbox.jsonl` — a moving target; the measured composition and its dated baseline live in the scope anchor document (`.moai/docs/learning-channel-scope.md`), never in prose here. The constitution names the orchestrator as the drain actor, but until this skill there was **zero mechanical drain code** — the drain existed only as a doctrine paragraph (`moai-constitution.md:147`). This skill closes that gap in user-owned surfaces, without touching the frozen Go applier (`internal/harness/applier.go:22` — its write-flag stays `false`; REQ-LSEL-003: bypass, never unfreeze).
**Channel scope (bounded claim):** the inbox records failure-event stubs only — the two wired families `tool_failure:<tool>:<sig>` and `test_fail:<pkg>:` (the test-fail family is wired via the evidence writer's test-fail path; the writer itself is untouched here). It does not capture defect families that produce neither a tool failure nor a test failure — those travel through the human-mediated loop (lane discovery → lead judgment → auto-memory `feedback_*.md` + `MEMORY.md` record), which is their learning channel. Numbers live only in the anchor document.
The drain is split into a **mechanical core** (`drain.sh`, deterministic, testable) and a **model-mediated layer** (this SKILL.md + your judgment, invoked for M2+ importance refinement and proposal drafting).
The mechanical core — `drain.sh`
`drain.sh` is a portable bash + jq script that lives next to this SKILL.md. It performs the deterministic half of the drain:
drain.sh --inbox <path-to-lessons-inbox.jsonl> --state-dir <path-to-lsel-state>
Pipeline (REQ-LSEL-009 + AC-LSEL-009 / AC-LSEL-010):
1. **Companion offset** — read `<state-dir>/drain-offset.json` (seed `{"offset":0}` if absent). The inbox is append-only and is NEVER mutated; the offset marks consumed stubs (SPEC-HARNESS-RATCHET-REWIRE-001 D3 companion-offset pattern). 2. **Slice** — read stubs from the offset onwards (`tail -n +<offset+1>`). 3. **Drain-side severity filter** (AC-LSEL-010) — discard noise BEFORE clustering:
- `tool_failure:Bash:UnknownFailure` — the opaque ~65% timeout/sandbox bucket (the dominant
noise share; report §2).
- `tool_failure:Bash:SandboxViolation` — environment constraint, not a code defect.
- any `*:TimeoutError` (Bash + MCP timeouts).
The filter is drain-side because `internal/hook/failure_observer.go` (the inbox writer) is OUTSIDE the six loop-writable surfaces (plan.md §F.1 [DECISION RESOLVED]), so the loop cannot edit the writer — it filters on read instead. 4. **Cluster** by `event_key` with frequency count, first/last seen, and up to 3 sample summaries. 5. **Singleton gate** — discard clusters with `frequency < 2` (single-occurrence noise per the constitution Lessons Protocol drain paragraph). 6. **Importance** — score each survivor with a Generative-Agents-style 1-10 gate: `importance = min(10, frequency)` (frequency as proxy; the model augments this in M2+ with a severity hint and retrieval-weighted judgment). 7. **Emit** candidates to `<state-dir>/clusters.json`; advance the companion offset.
`clusters.json` schema
{
"drained_at": "2026-08-04T08:41:00Z",
"offset_before": 0,
"offset_after": 624,
"total_read": 624,
"noise_discarded": 533,
"singletons_discarded": 4,
"candidates": [
{
"event_key": "tool_failure:Agent:UnknownFailure",
"frequency": 41,
"first_seen": "...",
"last_seen": "...",
"sample_summaries": ["...", "...", "..."],
"source": "tool:Agent",
"importance": 10
}
]
}Empty-delta no-op
If the inbox has not grown past the offset, `drain.sh` writes an empty-candidate `clusters.json` and leaves the offset unchanged. Not a failure (acceptance.md §E edge case).
The model-mediated layer (you, when invoked)
`drain.sh` produces the deterministic candidate set. When this skill is invoked for a real curation pass (M2+), your job on top of the mechanical output is:
- **Read `clusters.json`** and rank candidates by `importance` then `frequency`.
- **Augment importance** with a severity hint the mechanical core cannot see: a recurring
`Bash:ExitError` cluster points at a real command-shape defect (high signal); a recurring `Agent:ContextCancelled` cluster may be session-teardown noise (lower signal). Record the rationale in the candidate's prose when you draft the M2 proposal —
Read more
name: hns-lsel-curator description: > Local Self-Evolution Loop (LSEL) curator — the CLUSTER + drain engine for the GOOS-local PROPOSE→APPLY seam closure (SPEC-LSEL-LOCAL-EVOLUTION-001). Companion-offset drain of .moai/lessons-inbox.jsonl with a drain-side severity filter that drops the ~65% Bash-timeout/sandbox noise, event_key clustering with a frequency gate, and a Generative-Agents-style 1-10 importance score. Candidates stage at .moai/state/lsel/clusters.json. M1 = drain only (NO PROPOSE, NO APPLY, NO memory/ writes). allowed-tools: Read, Grep, Glob, Bash user-invocable: false metadata: version: "0.2.0" category: "harness" status: "active" updated: "2026-08-26" tags: "lsel,self-evolution,drain,cluster,harness,dogfood"
hns-lsel-curator — LSEL CLUSTER + drain engine
> **Namespace:** `hns-lsel-*` is user-owned dogfood (CLAUDE.local.md §24). This skill is > NOT mirrored into `internal/template/templates/` — it lives only in this repo. Graduation > to `moai-lsel-*` + 16-language distribution is a separate SPEC (out of scope per spec.md §G). > > **M1 scope:** drain + cluster + stage candidates. NO APPROVE, NO APPLY (M3). > **M2 scope:** drain + cluster + **PROPOSE shadow** (no APPROVE, no APPLY). The PROPOSE stage > emits shadow proposals + self-critiques; APPROVE/APPLY land in M3 via the fresh > `hns-lsel-applier` path. M2 does NOT write to `memory/` — the first `feedback_*.md` topic > file is an M3+ deliverable after APPROVE.
What this skill does
The MoAI-ADK repo accumulates failure-event stubs in `.moai/lessons-inbox.jsonl` — a moving target; the measured composition and its dated baseline live in the scope anchor document (`.moai/docs/learning-channel-scope.md`), never in prose here. The constitution names the orchestrator as the drain actor, but until this skill there was **zero mechanical drain code** — the drain existed only as a doctrine paragraph (`moai-constitution.md:147`). This skill closes that gap in user-owned surfaces, without touching the frozen Go applier (`internal/harness/applier.go:22` — its write-flag stays `false`; REQ-LSEL-003: bypass, never unfreeze).
**Channel scope (bounded claim):** the inbox records failure-event stubs only — the two wired families `tool_failure:<tool>:<sig>` and `test_fail:<pkg>:` (the test-fail family is wired via the evidence writer's test-fail path; the writer itself is untouched here). It does not capture defect families that produce neither a tool failure nor a test failure — those travel through the human-mediated loop (lane discovery → lead judgment → auto-memory `feedback_*.md` + `MEMORY.md` record), which is their learning channel. Numbers live only in the anchor document.
The drain is split into a **mechanical core** (`drain.sh`, deterministic, testable) and a **model-mediated layer** (this SKILL.md + your judgment, invoked for M2+ importance refinement and proposal drafting).
The mechanical core — `drain.sh`
`drain.sh` is a portable bash + jq script that lives next to this SKILL.md. It performs the deterministic half of the drain:
drain.sh --inbox <path-to-lessons-inbox.jsonl> --state-dir <path-to-lsel-state>
Pipeline (REQ-LSEL-009 + AC-LSEL-009 / AC-LSEL-010):
1. **Companion offset** — read `<state-dir>/drain-offset.json` (seed `{"offset":0}` if absent). The inbox is append-only and is NEVER mutated; the offset marks consumed stubs (SPEC-HARNESS-RATCHET-REWIRE-001 D3 companion-offset pattern). 2. **Slice** — read stubs from the offset onwards (`tail -n +<offset+1>`). 3. **Drain-side severity filter** (AC-LSEL-010) — discard noise BEFORE clustering:
- `tool_failure:Bash:UnknownFailure` — the opaque ~65% timeout/sandbox bucket (the dominant
noise share; report §2).
- `tool_failure:Bash:SandboxViolation` — environment constraint, not a code defect.
- any `*:TimeoutError` (Bash + MCP timeouts).
The filter is drain-side because `internal/hook/failure_observer.go` (the inbox writer) is OUTSIDE the six loop-writable surfaces (plan.md §F.1 [DECISION RESOLVED]), so the loop cannot edit the writer — it filters on read instead. 4. **Cluster** by `event_key` with frequency count, first/last seen, and up to 3 sample summaries. 5. **Singleton gate** — discard clusters with `frequency < 2` (single-occurrence noise per the constitution Lessons Protocol drain paragraph). 6. **Importance** — score each survivor with a Generative-Agents-style 1-10 gate: `importance = min(10, frequency)` (frequency as proxy; the model augments this in M2+ with a severity hint and retrieval-weighted judgment). 7. **Emit** candidates to `<state-dir>/clusters.json`; advance the companion offset.
`clusters.json` schema
{
"drained_at": "2026-08-04T08:41:00Z",
"offset_before": 0,
"offset_after": 624,
"total_read": 624,
"noise_discarded": 533,
"singletons_discarded": 4,
"candidates": [
{
"event_key": "tool_failure:Agent:UnknownFailure",
"frequency": 41,
"first_seen": "...",
"last_seen": "...",
"sample_summaries": ["...", "...", "..."],
"source": "tool:Agent",
"importance": 10
}
]
}Empty-delta no-op
If the inbox has not grown past the offset, `drain.sh` writes an empty-candidate `clusters.json` and leaves the offset unchanged. Not a failure (acceptance.md §E edge case).
The model-mediated layer (you, when invoked)
`drain.sh` produces the deterministic candidate set. When this skill is invoked for a real curation pass (M2+), your job on top of the mechanical output is:
- **Read `clusters.json`** and rank candidates by `importance` then `frequency`.
- **Augment importance** with a severity hint the mechanical core cannot see: a recurring
`Bash:ExitError` cluster points at a real command-shape defect (high signal); a recurring `Agent:ContextCancelled` cluster may be session-teardown noise (lower signal). Record the rationale in the candidate's prose when you draft the M2 proposal —
Agentic development harness for Claude Code — SPEC-driven plan/run/sync, TRUST 5 quality gates, model+effort routing, and Claude×GLM multi-LLM cost control. Single Go binary, 16 languages, zero deps.
Other skills on moai-adk.
More skills from other plugins.
agentmail
Use your assigned AgentMail inbox to read email tasks, explicitly send or reply, and check delivery. Provided automatically by…
adr-create
Create a new Architecture Decision Record with sequential numbering and AgentDB registration
Questions about hns-lsel-curator.
- Which coding agents can use hns-lsel-curator?
- hns-lsel-curator installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

