- scripts/agent.sh <name>: launches interactive pi TUI in the container with contracts + optional mission + agent identity + named session + optional workspace/tools; the Mosaic alternative to vanilla pi - pi adapter: MOSAIC_INTERACTIVE branch (clean TUI, no -p, no initial prompt); headless exec rebuilt via positional args (no word-splitting on the request); MOSAIC_AGENT_NAME optional in headless - loader: AGENT IDENTITY section when the launcher names the agent - compose: fixed command removed (request defaults live in run-agent.sh); MOSAIC_INTERACTIVE/MOSAIC_AGENT_NAME passthrough - docs/TOOLS.md: full on-demand tool reference; AGENTS.md routes to it - RELEASE -> 0.0.8 (container change); build verified Closes #35
4.3 KiB
4.3 KiB
unslop-hook
Mechanical AI-tell enforcement for pi seats. Anti-drift gate for the writing standard in SYSTEM.md / ms-unslop: prose distribution alone decays over long sessions; this check cannot forget.
lists.json: committed machine source for every list the checker enforces: words, phrases, punct rules, regex patterns, density thresholds. Each entry carries provenance (ms-unslop:<pattern id>orsystem-md), the mention convention, and the documented divergence of the density gate from SYSTEM.md's outright em-dash ban. Edit lists here, not in code.unslop-check.js: dependency-free checker (node CLI + module) driven by lists.json. Loads and schema-validates the lists on first use and hard-fails closed: empty, unparseable, or invalid lists throw. Detects banned vocabulary, chatbot/sycophancy phrases, filler phrases, em/en dashes, curly quotes,not just X but Y. Strips fenced and inline code first, so quoted code is never flagged. Exit 0 clean, 1 violations, 2 gate broken (lists unreadable, never a clean verdict).extension.ts: pi extension.message_endchecks finalized assistant text and notifies the operator (TUI/RPC).before_agent_startreads the most recent assistant reply from the session file and, if it carries tells, injects a correction notice the model sees on its next turn./unslopreports session stats. Violation state lives in the session file, so the injection path survives restart, resume, fork, and reload (an in-memory pending flag was measured dead across print-mode turns, 2026-08-19). A broken lists.json fails closed: checks stop,broken_lists/skipped_brokenevents log the reason, operator notified once, seat keeps running.test-unslop-check.js: unit tests with red and green controls.
Use
node test-unslop-check.js # suite
node unslop-check.js <file> # CLI check
UNSLOP_LISTS=<path> node unslop-check.js <file> # alt lists location
pi -e ~/.mosaic/tools/unslop-hook/extension.ts # ad-hoc load
# deploy: copy dir to ~/.pi/agent/extensions/unslop-hook/ or seat .pi
# equivalent, or list it in settings.json "extensions"
Env: MOSAIC_UNSLOP_HOOK=0 disables. MOSAIC_UNSLOP_LOG=<path> appends JSONL
events (loaded / flagged / notice_injected / checked / broken_lists /
skipped_broken) for headless evidence. UNSLOP_LISTS=<path> overrides the
lists.json location for both CLI and extension.
Verified here (2026-08-19)
- Unit suite 24/24 (8 behavioral, 11 loader/CLI, 5 review follow-up), red and green controls both exercised, including exit-2 on broken lists and on an unreadable input file (S3).
- CLI: slop file exit 1, clean file exit 0, broken lists exit 2 with the fault named on stderr.
- Extension, healthy path (print mode, zai/glm-5.3:low): startup probe loads lists.json, reply checked clean.
- Extension, broken-lists path (print mode):
broken_listsat startup,skipped_brokenper turn, seat survives, reply still delivered. - Earlier live evidence (pre-C1, inline lists): forced-slop turn flagged; fresh-process follow-up injected the notice and the reply came back clean; full TUI trial (notify line, injection, /unslop stats) on session vision-unslop.
- Log evidence in session scratchpad.
Limits
/unslopcommand not tested headless (print mode has no command surface); it is a thin stats wrapper.- En dash flag fires on typographic ranges too (2–3); acceptable for fleet prose, revisit if it noisifies technical writing.
- Notice injection is a nudger, not a blocker. Output already streamed to the user stays as-is; correction lands on the next turn.
- A broken lists.json latches for the session: repairing the file mid-session does not revive checks until the seat restarts. Acceptable for an advisory gate (review S1).
- The fail-closed operator notification requires a UI. Print-mode sessions
log
skipped_brokenbut notify nobody (review S2). - The word/phrase lists are the mechanical subset of ms-unslop only, keyed to pattern ids in lists.json. Style judgments (voice, rhythm, structure) stay in the skill, not the gate.
Promotion path
Stack issue (A4): checker shared as the single source for a matching Claude Code Stop-hook script; lists versioned beside SYSTEM.md contract text.