CtrlK
BlogDocsLog inGet started
Tessl Logo

hns-lsel-applier

Local Self-Evolution Loop (LSEL) APPLY engine — the playback-only consumer of approved decision.json records that drives `.moai/hooks/lsel-apply.sh` for the GOOS-local PROPOSE→APPLY seam closure (SPEC-LSEL-LOCAL-EVOLUTION-001 M3). Reads an approved decision.json, validates the target against the frozen allowlist (.claude/lsel/frozen-allowlist.json), mechanically refuses execution-meta targets lacking a synchronous-approval marker, applies the referenced diff.patch, appends an apply-ledger.jsonl row, and commits one lsel-<proposal-id>-tagged Conventional Commit on the feature branch. M3 scope: APPLY bypass closure only (the frozen Go applier stays frozen — its write-flag at internal/harness/applier.go:22 stays false; REQ-LSEL-003).

62

Quality

74%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./.claude/skills/hns-lsel-applier/SKILL.md
SKILL.md
Quality
Evals
Security

hns-lsel-applier — LSEL APPLY 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).

Token discipline. This body deliberately avoids the literal identifier of the frozen Go applier's write-flag and the literal name of the orchestrator-only user-question channel. Both are referenced by location and role (e.g. "the write-flag at internal/harness/applier.go:22", "the orchestrator's synchronous user gate") so the REQ-LSEL-003 invariant-grep and the E4 subagent-boundary grep over LSEL surfaces read zero literal matches. The invariants themselves are stated in plain English.

What this skill does

The LSEL loop's PROPOSE→APPLY seam was dead in production: Applier.Apply never ran (manifest.jsonl absent), CuratorDispatch had 0 production callers, and the frozen Go applier's write-flag at internal/harness/applier.go:22 (kept false) is the apply dead-switch (REQ-LSEL-003 — M3 keeps it false by BYPASS, never unfreeze). The M3 closure routes APPLY through a parallel user-owned applier that writes only to the six evolvable surfaces (spec.md §B.3), while the frozen Go applier stays byte-for-byte frozen. Design SSOT: .moai/reports/moai-local-self-evolution-design-20260804.html §4 ("동결된 Go applier를 우회하는 병렬 사용자 소유 applier를 세운다" — build a parallel user-owned applier that bypasses the frozen Go one) + §7 (the two-round critique moved the allowlist OUT of the evolvable skill files into a frozen meta file, and added execution-meta files to the forced-gate set).

The APPLY engine is the playback hook .moai/hooks/lsel-apply.sh plus this skill's model-mediated judgment (target validation nuance, approval-marker provenance, blast- radius reasoning the mechanical hook cannot see). The hook is the load-bearing safety floor; this skill is the consumer-facing surface that decides WHICH approved decision to feed it next and how to interpret refusal.

The APPLY pipeline

lsel-apply.sh <decision.json> performs five steps. Steps 1-2 are the safety floor; steps 3-5 are the playback.

  1. Frozen-allowlist hard-reject (REQ-LSEL-001 / AC-LSEL-001). The target path in decision.json is matched against the frozen_patterns regex list in .claude/lsel/frozen-allowlist.json. A match → REFUSE: a row is appended to .moai/logs/lsel-reject.log naming the rejected path and category frozen-path, NO file is written, and the hook exits 2.
  2. Execution-meta forced-gate (REQ-LSEL-002 / AC-LSEL-005 D3 self-amending- handcuffs). If the target matches one of the four execution_meta categories — (i) the frozen allowlist meta file itself, (ii) an applier/curator skill body (hns-lsel-applier/, hns-lsel-curator/), (iii) the apply hook (.moai/hooks/lsel-*.sh), (iv) the settings.local.json hook-registration subblock — the hook checks decision.json for a synchronous-approval marker (a synchronous_approval object with decision: "approved", produced by the orchestrator's synchronous user gate). No marker → REFUSE: reject-log row with category execution-meta, exit 3, no write. With marker → proceeds (the refusal is keyed on the absent marker, NOT on the category match alone). The refusal semantics mirror the M2 csa_refusal_test.sh fixture exactly.
  3. Apply the diff.patch via git apply (playback of an already-approved decision). Only the paths declared in the patch are staged — never git add -A (working-tree hygiene).
  4. Append the apply-ledger row to .moai/state/lsel/apply-ledger.jsonl: {proposal_id, target_surface, ts, result:"applied", commit_sha, category}. This is the manifest the frozen Go applier never produced, finally real in user-owned space.
  5. Commit the staged change as ONE feat(lsel-<proposal-id>): ... Conventional Commit on the current (feature) branch (REQ-LSEL-004). The ledger row's commit_sha is backfilled from the commit's short SHA.

A no-arg invocation is a clean no-op (exit 0) so an empty approved-queue does not derail a loop pass.

The model-mediated layer (you, when invoked)

When this skill is invoked to drive an APPLY pass, your job on top of the mechanical hook is:

  • Read the proposal's proposal.md + self-critique.md at .moai/state/lsel/proposals/<id>/. A proposal with status: blocked (any UNRESOLVED self-critique objection) MUST NOT be fed to the hook — return a blocker report instead.
  • Confirm the approval marker's provenance. The synchronous_approval object must carry a real orchestrator-produced approval artifact (the synchronous user-question channel the orchestrator owns per CLAUDE.md §8). A marker the loop fabricated for itself is the self-amending-handcuffs failure mode (REQ-LSEL-002); the hook's mechanical check is the floor, your provenance judgment is the ceiling. This skill is a subagent mechanism and NEVER invokes the orchestrator-only user-question channel; return a blocker report and let the orchestrator run the gate.
  • Re-verify the frozen-allowlist invariant by grepping the write-flag at internal/harness/applier.go:22 — it MUST stay false. If M3's bypass ever drifts toward unfreezing the Go applier, return a blocker (AP-LSEL-002).

What this skill does NOT do

  • No unfreezing of the Go applier — the write-flag at internal/harness/applier.go:22 stays false (REQ-LSEL-003). The bypass is parallel and user-owned; the frozen applier is reference-only.
  • No edits to frozen doctrine — internal/template/templates/**, .claude/rules/moai/**, CLAUDE.md, retained agents, moai-* skills, the frozen Go applier / curator_dispatch.go, and .moai/config/sections/** are byte-for-byte untouched. The allowlist hard-rejects them (step 1).
  • No new-apply / self-approve / allowlist-amend primitive in lsel-apply.sh (REQ-LSEL-008). The hook only consumes already-approved decisions; it does not author proposals or bless them. The M4 verify.sh runs only AFTER an apply has committed — it does not create a new apply; it never self-approves.
  • No user-question invocation — subagent boundary (CLAUDE.md §8). Return a blocker report; the orchestrator runs the synchronous gate.

VERIFY stage (M4 — REQ-LSEL-013 / AC-LSEL-015)

After an apply commits a proposal, VERIFY proves the apply was safe. VERIFY has two layers — both MANDATORY:

(a) Mechanical layer — verify.sh (bash-testable)

verify.sh --proposal-dir <p> --repo-root <r> [--timeout SECS] [--feedback-file <f>] runs the proposal's frontmatter verify_command with a timeout-retry-once policy and auto-reverts on a second failure:

  • 2-attempt policy. Attempt 1 runs. On SUCCESS → verified:true, stop. On TIMEOUT-class failure → attempt 2 (flaky tolerance — report §10 P3: "retry once on timeout so a correct proposal isn't flipped by noise"). On NON-TIMEOUT-FAIL → attempt 2 (allows the "second non-timeout failure" of AC-LSEL-015 clause 3 to materialize before revert fires).
  • Attempt 2: SUCCESS → verified:true. Any failure (timeout OR non-timeout) → verified:false + auto git revert lsel-<proposal-id> + the proposal's feedback_*.md is marked verified: false.
  • The outcome is appended to the apply ledger as a {"stage":"verify","verified":true|false,...} row — the load-bearing signal.

(b) MANDATORY /moai gate superset (model-mediated)

/moai gate (lint+format+type+test) is MANDATORY after every apply — it is NOT optional. A bash hook cannot invoke a Claude Code slash command directly, so the gate runs MODEL-SIDE: when this skill drives an APPLY pass, the orchestrator/model runs /moai gate after the mechanical apply + verify. The proposer-authored verify_command alone is circular (report §11 mustFix B#6 / AP-LSEL-004): a proposer can author a verify_command that its own change satisfies. /moai gate is the independent check — lint, format, type-check, and the test suite exercise surfaces the proposal never touched. Treat a mechanical verify_command PASS without a green /moai gate as an unverified apply.

Model-mediated layer (you, when invoked)

  • After lsel-apply.sh commits and verify.sh reports, run /moai gate (the MANDATORY superset). If the gate fails, the apply is unverified even if verify.sh reported verified:true — treat it as a VERIFY failure and revert.
  • A revert (whether auto-fired by verify.sh or gate-driven) MUST be surfaced to the orchestrator as a blocker report — the orchestrator, not this skill, confirms a revert with the user. Never run /moai gate's user-facing surface from inside this subagent mechanism; return a blocker report.

Verification (run before declaring an APPLY+VERIFY pass complete)

# M4 VERIFY characterization test (AC-LSEL-015) — hermetic temp repo:
.claude/skills/hns-lsel-applier/verify_test.sh

# the verify ledger row carries the outcome:
grep '"stage":"verify"' .moai/state/lsel/apply-ledger.jsonl

Verification (run before declaring an APPLY pass complete)

# 1. APPLY characterization test (AC-001/002/005/008/013) — hermetic temp repo:
.claude/skills/hns-lsel-applier/apply_test.sh

# 2. Rollback-rehearsal SHIP GATE (AC-014):
.claude/skills/hns-lsel-applier/rollback_rehearsal_test.sh

# 3. REQ-LSEL-003 frozen-flag re-verify (post-apply). The frozen Go applier's
#    write-flag at internal/harness/applier.go:22 MUST read `false`, and no LSEL
#    surface (skills/hooks/state/allowlist) references that identifier as mutable.
#    (The literal identifier is intentionally not written here; find it at line 22
#    of the frozen file and grep LSEL surfaces for it — expect zero hits.)
sed -n '22p' internal/harness/applier.go   # MUST show the `= false` write-flag line

# 4. The apply ledger carries the new row:
tail -1 .moai/state/lsel/apply-ledger.jsonl

Cross-references

  • SPEC: .moai/specs/SPEC-LSEL-LOCAL-EVOLUTION-001/{spec,plan,acceptance,progress}.md
  • Design report (SSOT): .moai/reports/moai-local-self-evolution-design-20260804.html §4 (user-owned parallel applier), §7 (allowlist relocation + execution-meta forced gate), §10 P3, §11 mustFix A#1/A#5/A#8.
  • Frozen applier (reference only): internal/harness/applier.go:22 (the frozen write-flag), internal/harness/curator_dispatch.go.
  • Curator (PROPOSE stage, M2): .claude/skills/hns-lsel-curator/SKILL.md (CSA forced-gate doctrine + the Tier-4 DEAD finding).
  • CSA refusal fixture: .claude/skills/hns-lsel-curator/csa_refusal_test.sh (the refusal rule this hook enforces mechanically).
  • Namespace guard: internal/template/split_namespace_test.go, internal/template/internal_content_leak_test.go (must NOT flag a hns-lsel-applier leak — this skill is dogfood, never templated).
Repository
modu-ai/moai-adk
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.