numen-tech/slopornot · Archived

agentic-humanizer

Humanizes AI-generated text with a 5-pass rewrite workflow in English and six other languages, optional saved preferences, and optional stylometric voice matching from a writing sample. Works without Slop or Not. When Slop or Not Pro is reachable, adds on-device AI detector scoring (English only), native-language readability checks, Text Cleanup, and cleanup stats. Use when the user invokes /agentic-humanizer or asks to humanize text.

First seen May 21, 2026

Installation

$ npx skills add numen-tech/slopornot --skill agentic-humanizer

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from numen-tech/slopornot.

npx skills add numen-tech/slopornot

Browse all from numen-tech/slopornot

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Declared
Codex Declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Declared
Cline Not declared
OpenCode Declared

Repository health

Stars 47
License LICENSE
Default branch main
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Version0.3.0
LicenseMIT
Compatibilityclaude-code codex cursor gemini-cli opencode
Allowed toolsRead, Bash, AskUserQuestion
Declared agents claude-code cursor codex gemini opencode

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 38,887 B
  • docs README.md 5,910 B
  • docs SUMMARY.md 463 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 56 installs

SKILL.md

Agentic Humanizer

A 5-pass AI humanizer. It always runs the core rewrite workflow; Slop or Not Pro adds measured on-device AI detector checks.

  • Without Slop or Not: runs the full rewrite workflow.
  • With Slop or Not Pro: adds on-device AI detector scoring, readability, Text Cleanup, and

cleanup stats.

Supported languages: English, Spanish, German, Italian, Swedish, Danish, and Norwegian (Bokmal and Nynorsk). The AI detector score is English only; other languages use native readability and per-language tells. See references/multilingual.md.

Slash command: /agentic-humanizer [paste text]

Inline overrides: /agentic-humanizer language=<code> variant=<spec> dialect=us|uk grade=N level=<band> tone=casual|professional|academic length=±10|exp|trim threshold=N max=N voice=/path/to/file.txt|off voice-skip skip-interview [paste]

language=<code> and variant=<spec> set the target language and variant (for example language=de variant=de-AT). dialect=us|uk is a legacy English alias: dialect=us equals language=en variant=en-US, dialect=uk equals language=en variant=en-GB. grade=N sets the Flesch-Kincaid target and is English only; level=<band> sets the reading-level band (elementary|middle|high_school|college|graduate) for any language. Explicit language=/variant= win over dialect=. Setting language= without variant= uses that language's default variant from the registry (the first variant listed, or other:<code> for an unsupported language with no registry entry). Setting variant=<tag> without language= infers the base language from the variant's BCP-47 prefix (for example variant=de-AT -> language=de); if the prefix is unsupported, keep that bare prefix as the language, use the inline variant, and warn. See references/multilingual.md for supported codes and variants.

What this skill does

  1. Detects the host harness (Claude Code, Codex, Cursor, Gemini CLI,

OpenCode, or generic).

  1. Handles profile and voice management commands before any rewrite.
  2. Resolves rewrite preferences from inline overrides, saved profile, or the

harness interview.

  1. Optionally resolves a writing sample and extracts a cached stylometric

fingerprint. Voice matching does not require Slop or Not.

  1. Probes whether Slop or Not Pro is reachable via MCP or CLI.
  2. Runs the 5-pass humanization workflow:

- Core mode logs unscored iterations. - Slop or Not Pro runs Text Cleanup, detection, and readability checks.

  1. Returns the final text, loop history, highest-impact edits, and, when Slop

cleanup ran, a Text Cleanup summary.

Step 1: Detect the harness

Identify which harness is running by checking for the harness's distinctive question tool. Use the first match:

Harness Distinctive tool present? Read this file
Claude Code AskUserQuestion harnesses/claude-code.md
Codex CLI tool/requestUserInput (or askuserquestion) harnesses/codex.md
Cursor AskQuestion harnesses/cursor.md
Gemini CLI ask_user (or equivalent structured-question tool) harnesses/gemini-cli.md
OpenCode OpenCode's built-in question tool, or AUQ MCP harnesses/opencode.md
Anything else (e.g. ChatGPT Skills) n/a; fall back to plain text harnesses/generic.md

Do not load the harness file yet. Save the choice for Step 3.

Step 2: Profile management commands

The user can manage their saved profile with these subcommands:

Command Action
/agentic-humanizer show profile Print ~/.agentic-humanizer/profile.json (or "no profile saved").
/agentic-humanizer reset rm ~/.agentic-humanizer/profile.json and confirm.
/agentic-humanizer set language=de variant=de-AT level=high_school tone=casual length=±10 Write a profile from inline params without running the interview. Recognized keys: language, variant, dialect (legacy English alias), grade (English only), level, tone, length. Any subset is allowed; missing keys keep their current value or use the default if no profile exists. When language changes without an explicit variant, reset variant to that language's default from references/multilingual.md (the first variant listed, or other:<code> for an unsupported language) instead of keeping the old one, so the saved pair stays consistent (for example set language=de on an English profile writes variant=de-DE, not en-US). A legacy dialect= change without an explicit variant resets variant to that alias's specific English variant, not the registry default: dialect=us writes variant=en-US and dialect=uk writes variant=en-GB. When variant=<tag> is given without language=, infer the base language from the variant's BCP-47 prefix (for example set variant=de-AT -> language=de) and update the saved language accordingly; if the prefix is unsupported, keep that bare prefix as language, keep the inline variant, and warn that the language has no curated support. For English, keep the level fields consistent: level= sets readinglevel and derives targetgrade from the band midpoint (elementary 4, middle 7, highschool 10, college 13, graduate 17), and grade=N sets targetgrade=N and readinglevel to that grade's band; when the saved language becomes non-English, write targetgrade: null (the loop reads reading_level).
/agentic-humanizer show voice Print ~/.agentic-humanizer/voice-fingerprint.json if present, plus the sample path; otherwise say no voice is saved.
/agentic-humanizer reset voice Remove ~/.agentic-humanizer/voice.txt and ~/.agentic-humanizer/voice-fingerprint.json, then clear voice fields from the profile without deleting the rewrite preferences.
/agentic-humanizer set voice=/path/to/file.txt Save the profile's voicepath, clear voiceskip, and use that path on future runs. Do not extract the fingerprint until the next rewrite call.

When you see one of these subcommands, execute it and stop. Do not probe Slop or run the loop.

Step 3: Resolve rewrite preferences

Detect the source language first. Before reading the profile or running the interview, detect the language of the pasted text with the host LLM (use the first ~300 words; no backend needed, so this works in both Core and Slop or Not Pro modes). Store detectedlanguage (a base code such as de) and, when the orthography makes it clear, a detectedvariant_hint (such as de-DE). Normalize the code per references/multilingual.md (Norwegian Bokmal becomes nb, never no). If no text has been pasted yet, defer detection until it is. If the text is under ~20 words or mixed, treat the language as ambiguous.

Profile resolution order:

  1. Inline overrides (language=, variant=, dialect=, grade=,

level=, tone=, length=) -> use them; do not read the profile for the overridden keys. Inline language=/variant= also override detection. When language= is given without variant=, set the variant to that language's default from references/multilingual.md (the first variant listed), not the profile's variant, so the pair stays consistent (for example language=de alone resolves to variant=de-DE; an unsupported language with no registry entry, such as language=fr, resolves to variant=other:fr). When variant=<tag> is given without language=, infer the base language from the variant's BCP-47 prefix (for example variant=de-AT -> language=de, variant=es-419 -> language=es); if the prefix is unsupported, keep that bare prefix as the language, keep the inline variant, and warn that the language has no curated support. If an explicit language= is also present and conflicts with the variant's base language, language= wins and the run warns. For English, when level= is set without grade=, derive targetgrade from the resolved band midpoint (elementary 4, middle 7, highschool 10, college 13, graduate 17); an explicit grade=N always wins. Inline overrides apply per key; resolve any key not supplied inline through rules 2 to 4 below rather than leaving it unset.

  1. skip-interview flag -> use the saved profile if present. With no

profile, keep the detected source language; for the variant, use detectedvarianthint when it is a valid variant for the resolved language, otherwise the resolved language's default variant from references/multilingual.md. Default the rest (High school, Professional, ±10%); fall back to English/en-US only when detection is ambiguous or no text was pasted. For English, derive target_grade 10 from the High school band.

  1. Saved profile at ~/.agentic-humanizer/profile.json present:

- If detectedlanguage equals the profile's language, or detection is ambiguous, use the profile silently and skip the interview. Never re-prompt a user who already has a profile unless they ask. - If detectedlanguage differs from the profile's language (unambiguous), the call does not run in the profile's language: an inline language= wins, otherwise detection wins, and inline variant/tone/length/level/grade still override the profile per key. Resolve language, variant, reading level, tone, length, and English target_grade for this case using the decision table in references/profile-resolution.md. Do not prompt and do not rewrite the profile. Carry the table's matching note into Step 7.

  1. No saved profile -> run the harness interview for any rewrite keys not

already set by inline overrides (rule 1). With some keys set inline, ask only the remaining ones; with none set inline, run the full interview as below.

Read the saved profile with:

PROFILE=~/.agentic-humanizer/profile.json
[ -f "$PROFILE" ] && cat "$PROFILE"

If the file is missing or is malformed JSON, treat it as absent and run the interview. If it is parseable, first apply the back-compat normalization in the next paragraph (it maps a legacy dialect/targetgrade profile to language/variant/readinglevel), then judge completeness: only treat the profile as absent (and run the interview) when it still lacks the resolved rewrite settings (language, variant, readinglevel, tone, lengthpolicy) after that mapping. Version 1 and version 2 profiles, which carry dialect and targetgrade rather than the v3 keys, are complete once normalized and load without re-prompting. Missing voice fields use their defaults in Step 4. If a parseable profile has voiceskip but is still missing rewrite keys after normalization, ignore it for the rewrite interview but still honor voice_skip in Step 4.

Back-compat (read any older profile as v3). A profile without a language field is English: set language="en" and map the legacy dialect to variant (us -> en-US, uk -> en-GB, other:<spec> -> variant: "other:<spec>"). Derive readinglevel from targetgrade using the band table in references/multilingual.md (3 to 5 -> elementary, 6 to 8 -> middle, 9 to 11 -> highschool, 12 to 14 -> college, 15 and above -> graduate; default highschool if targetgrade is absent). Read every existing field first so custom values are preserved, then rewrite the whole file as v3 on the next write. targetgrade drives termination only for English; for other languages the loop reads reading_level and maps via the registry.

Run the interview by reading the harness file selected in Step 1 and following its interview protocol. The interview stays four rewrite questions (plus a separate language-disambiguation step when detection is ambiguous). The selected harness may batch the conditional voice question when it is eligible; Step 4 handles that answer. Capture these rewrite settings here:

  • language (a base code such as en, de, es, it, sv, da, nb,

nn, or other) and variant (a BCP-47 tag or other:<spec>). Q1 confirms the detected language and offers that language's variants from references/multilingual.md. See "Interview Q1 and Q2" below.

  • readinglevel in {elementary, middle, highschool, college,

graduate}. For English also set targetgrade (the band midpoint: 4, 7, 10, 13, 17). For other languages the loop reads readinglevel via the registry.

  • tone in {casual, professional, academic}
  • length_policy in {±10, exp, trim}

Interview Q1 and Q2. Q1 confirms language and variant. When the language was detected unambiguously, present "Detected <language>. Which variant?" with that language's variants from references/multilingual.md plus "Other (different language)". When the language is ambiguous or unknown, ask the language first, then its variant; option-capped harnesses (Claude Code, Cursor, Gemini CLI, OpenCode) offer the three most likely languages plus "Other (different language)" to stay within their four-option limit, while plain-text and free-text harnesses (generic, Codex) may list them all. If the user picks "Other (different language)", capture the language name or code on the next turn, resolve it against the registry, and warn if it is unsupported (no curated tells or readability). Q2 covers the five reading-level bands; show each band's helper text in the resolved language's metric (for example "High school (LIX about 40 to 50)" for Swedish, "High school (Grade 9 to 11)" for English), drawn from the registry band table. Option-capped harnesses collapse College and Graduate into one "College or professional" option to fit the four-option limit, so Graduate is selected via inline level=graduate or grade=N there; generic and Codex keep all five bands. For Norwegian Nynorsk and unsupported languages, present the bands without a metric helper. Map Q1 to language (normalized) and variant; map Q2 to readinglevel (and targetgrade for English).

After the rewrite answers, ask one final yes/no question (use the same harness question tool):

"Save these as your default so I don't ask again next time? You can reset anytime with /agentic-humanizer reset."

If yes:

mkdir -p ~/.agentic-humanizer
cat > ~/.agentic-humanizer/profile.json <<EOF
{
  "language": "<en|de|es|it|sv|da|nb|nn|other>",
  "variant": "<en-US|en-GB|de-DE|de-AT|de-CH|es-ES|es-419|it-IT|sv|da|nb|nn|other:...>",
  "reading_level": "<elementary|middle|high_school|college|graduate>",
  "target_grade": <4|7|10|13|17 for en, else null>,
  "tone": "<casual|professional|academic>",
  "length_policy": "<±10|exp|trim>",
  "voice_path": "~/.agentic-humanizer/voice.txt",
  "voice_skip": false,
  "voice_fingerprint_hash": null,
  "saved_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "version": 3
}
EOF

targetgrade is meaningful only when language is en; write it as null for other languages, where the loop reads readinglevel. For English, keep targetgrade consistent with readinglevel (the band midpoint), including on the inline level= path.

Then continue to Step 4. Inline overrides on a future call always win over a saved profile for that one call only; they do not overwrite the file.

Step 4: Resolve voice sample

Read references/voice-fingerprint.md before running this step. Set voice_active=false by default.

Voice sample resolution order:

  1. Inline voice=off or voice-skip -> skip voice matching for this call.
  2. Inline voice=/path/to/file.txt -> use that sample for this call only.

If the path does not exist or is not readable, warn the user once, then fall through to rules 3 onward as if the inline override were absent.

  1. Saved profile.json has voice_path and that file exists -> use it.
  2. Default ~/.agentic-humanizer/voice.txt exists -> use it.
  3. Saved profile.json has "voice_skip": true -> skip silently.
  4. Otherwise -> use the conditional Q5 answer already captured by the

selected harness, or ask it now if the harness did not batch it:

> "Mimic a writing sample of yours?"

Options: Yes, No, Never ask again.

If Q5 is No, skip voice matching for this call. If Q5 is Never ask again, persist voice_skip without inventing rewrite preferences, then skip voice matching. Read any existing profile first:

  • A profile already exists (including one just saved in Step 3): rewrite it with

"voiceskip": true and "version": 3, preserving its current rewrite keys (language, variant, readinglevel, targetgrade, tone, lengthpolicy).

  • No profile exists (the user declined to save rewrite defaults in Step 3):

write a voice-only record holding just "voiceskip": true and "version": 3, with no rewrite keys. Do not fill them from the v3 defaults. Step 3 treats such a profile as incomplete for the rewrite interview, so the language, tone, and reading-level questions still run next time, while it still honors voiceskip here.

If Q5 is Yes, say exactly:

"Paste 200+ words as your next message."

Capture the next user turn as the sample. Validate it before writing:

  • Under 50 words: reject it, say the sample is too short, leave

voice_active=false, and continue without changing the profile.

  • 50-199 words: warn that 200+ words works better, then ask whether to

continue with the shorter sample or paste a longer one.

  • 200+ words: write it to ~/.agentic-humanizer/voice.txt.

For every accepted sample, use only the first 3000 words for fingerprint extraction. Hash the first 50 KB of the sample content:

VOICE_SAMPLE="<resolved-sample-path>"
head -c 51200 "$VOICE_SAMPLE" | shasum -a 256

Prefix the stored value with sha256:.

Fingerprint cache:

The cache lives at ~/.agentic-humanizer/voice-fingerprint.json. Validate it against every rule in references/voice-fingerprint.md Cache invalidation (file present, version: 1, samplehash match, all required fields populated). On a clean cache hit, use it silently and set voiceactive=true. On any invalidation trigger, treat it as a cache miss and run extraction.

On cache miss, run the extraction prompt from references/voice-fingerprint.md against the host LLM. Render the JSON fingerprint and ask:

"Looks right?"

Options: Yes, Edit, Re-extract.

  • Yes: write the approved JSON to

~/.agentic-humanizer/voice-fingerprint.json, then rewrite ~/.agentic-humanizer/profile.json so voicepath points to the resolved sample, voiceskip is false, voicefingerprinthash matches the sample hash, and version is 3. Use the same heredoc pattern as Step 3, replacing only those voice fields and preserving the rewrite preferences (language, variant, readinglevel, targetgrade, tone, length_policy):

``bash mkdir -p ~/.agentic-humanizer cat > ~/.agentic-humanizer/profile.json <<EOF { "language": "<keep current>", "variant": "<keep current>", "readinglevel": "<keep current>", "targetgrade": <keep current>, "tone": "<keep current>", "lengthpolicy": "<keep current>", "voicepath": "<resolved-sample-path>", "voiceskip": false, "voicefingerprinthash": "sha256:<current-sample-hash>", "savedat": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "version": 3 } EOF ``

Then set voice_active=true.

  • Edit: let the user correct the JSON inline. Validate it against the

required-field list in references/voice-fingerprint.md Required fields before saving. If the edit drops a required field, refuse to save and offer Re-extract.

  • Re-extract: ask what to change, then re-run extraction with that hint.

On harnesses without a structured-question tool (the generic fallback), the approval gate degrades to print-and-continue. See harnesses/generic.md Fingerprint approval.

Inline voice=/path/to/file.txt does not overwrite the default sample or saved profile path. It may refresh the shared fingerprint cache for that sample hash.

If extraction fails, if the sample is binary or unreadable, or if no host LLM is available for the extraction prompt, set voice_active=false, add the extraction-failure footer flag for Step 7, and continue without voice matching.

Step 5: Probe Slop or Not Pro

Set slopmode="llm-only" and slopbackend=null by default. Probing Slop selects the enhancement path only; it never decides whether the humanizer runs.

Run a real detecttext fixture call to verify both presence AND Pro tier. slop status succeeds for non-Pro; only detecttext Pro-gates.

Use this fixture for both paths:

In today's digital environment, organizations often adopt new software because it promises efficiency, but the real value depends on whether people can trust it. A useful tool should explain what it does, respect the user's context, and avoid turning simple decisions into complicated workflows. Clear documentation helps teams evaluate those tradeoffs before they commit time or money.

MCP path (try first):

Call mcpSlopOrNotdetecttext with the fixture and includereadability: true. If the tool call succeeds and the parsed response has a numeric score or aiprobability field, set slopmode="slop-or-not-pro" and slopbackend="mcp". Treat scores from score and aiprobability as 0-1 decimals unless the value is already greater than 1. For readability, read the Flesch-Kincaid grade from readability.scores[] where kind is fleschKincaidGradeLevel.

CLI path (try second):

Run via Bash with the app-bundle binary:

cat <<'EOF' | "/Applications/Slop Or Not.app/Contents/MacOS/slop" text --json
In today's digital environment, organizations often adopt new software because it promises efficiency, but the real value depends on whether people can trust it. A useful tool should explain what it does, respect the user's context, and avoid turning simple decisions into complicated workflows. Clear documentation helps teams evaluate those tradeoffs before they commit time or money.
EOF

If exit code is 0 AND stdout parses as JSON with one of these numeric score paths, set slopmode="slop-or-not-pro" and slopbackend="cli":

  • detection.result._0
  • detection.resultFewSentences._0
  • ai_probability

For CLI readability, read the grade from readability.scores[] where kind is fleschKincaidGradeLevel. The detection score (detection.result._0) is a 0-1 decimal: multiply by 100 for a percentage unless the value exceeds 1. Readability grades are never percentages.

The probe fixture above is English, so its readability block always returns kind: fleschKincaidGradeLevel. This call only proves Pro access; discard its readability value. Source-language readability is measured separately on the real source text in Step 6, where the returned kind depends on the source language (see references/multilingual.md).

If neither path is live, keep slop_mode="llm-only" and continue to Step 6. Do not skip the interview, voice matching, or rewrite loop.

Step 6: Run the loop

Use the language L resolved in Step 3 (which already applies, in precedence order, any inline language=, the base language inferred from a variant=-only override, the detected and confirmed language, and the saved profile). If L is not English, read references/multilingual.md (the registry: readability formulas, band mapping, code normalization). Read references/per-iteration-strategies.md (the per-iteration cookbook). Then load the tell catalogue for L's branch below. The language branch composes with, and does not replace, the 5-iteration schedule.

Preserve coverage. Rewrite, don't delete: keep every fact and section the source covers and preserve the core meaning. Removing an AI tell never means dropping content. Under lengthpolicy=trim, cut only redundancy, filler, and restated points, never a unique fact or a whole section; shorten a fact's phrasing rather than removing it. Length changes come only from the resolved lengthpolicy, never from silent omission.

Language branch: loading and termination

L is en (English). Read references/patterns.md (the canonical 33-pattern rewrite vocabulary), references/supplemental-ai-tells.md, and references/detection-guidance.md (a false-positive guard: what not to flag and which human-writing signals to preserve). Use the full detector path. Read the Flesch-Kincaid grade from scores[] where kind is fleschKincaidGradeLevel. If targetgrade is null or unset here (for example inherited from a non-English saved profile through a partial inline override), derive it from the resolved readinglevel band midpoint (elementary 4, middle 7, high_school 10, college 13, graduate 17) before the termination check; an explicit inline grade= always wins. Terminate per "Termination with Slop or Not Pro" below.

L is es, de, it, sv, da, or nb (supported non-English). Do NOT read references/patterns.md (it is English vocabulary). Read references/supplemental-ai-tells.md and the per-language tell file references/ai-tells/<L>.md (Norwegian Bokmal uses references/ai-tells/no.md, Bokmal section). Pass the normalized languagecode on every Slop or Not call. Read whatever score kind scores[] returns, label it by that kind, and map the value to a band using references/multilingual.md. The AI score is n/a: detecttext returns kind: "notenglish" with score: null for non-English input, so do not call it for readability convergence. Get readability under Slop or Not Pro with a single analyzereadability call; do not also call detecttext. Terminate on readability band membership (per-scale semantics in the registry) or after MAXITER; there is no AI threshold check.

L is nn (Norwegian Nynorsk). Do NOT read references/patterns.md. Read references/supplemental-ai-tells.md and references/ai-tells/no.md, Nynorsk section. Readability is not available (the app returns unsupportedlanguage), so skip analyzereadability. The AI score is n/a. Run all MAX_ITER iterations and select the final iteration by quality (same as Core mode). Warn the user: "Readability scoring is not available for Norwegian Nynorsk in this app version."

L is an unsupported language. Do NOT read references/patterns.md. Read references/supplemental-ai-tells.md only. The AI score is n/a. Do not call detecttext. Call analyzereadability with the normalized languagecode; if scores[] returns a known kind, log the value as advisory only and never use it for termination; if scores[] is empty, treat readability as unavailable. Run all MAXITER iterations and select the final iteration by quality (same as Core mode). Follow the unsupported-language policy in references/multilingual.md.

When voice_active=true, Iteration 2 and Iteration 5 consume the cached fingerprint using the contracts in references/per-iteration-strategies.md. No other iteration uses the voice fingerprint.

Constants (overridable via inline params when Slop or Not Pro is available):

  • AI_THRESHOLD = 40 (override: threshold=N)
  • MAX_ITER = 5 (override: max=N)
  • Grade tolerance: ±1

Slop or Not Pro setup

If slop_mode="slop-or-not-pro", run Text Cleanup on the source before Iteration 0. Store:

  • sourcecleanedtext
  • sourcecleanupstats

Use sourcecleanedtext as the Iteration 0 baseline. Score and analyze the cleaned source, not the raw source.

Core setup

If slopmode="llm-only", use the original source as Iteration 0. Do not call detecttext, analyzereadability, or cleantext.

Cleanup stats parsing

For MCP clean_text, decode content[0].text as JSON before reading:

  • cleaned_text
  • removed_invisibles
  • punctuation_replacements
  • homoglyphs_replaced
  • british_substitutions

For CLI cleanup, pipe the selected text into the app-bundle binary:

cat <<'TEXT_TO_CLEAN' | "/Applications/Slop Or Not.app/Contents/MacOS/slop" cleanup --json
<selected source or final text>
TEXT_TO_CLEAN

Then read:

  • cleanedText
  • Sum invisibleCounts[].count
  • Sum punctuationCounts[].count
  • Sum homoglyphCounts[].count
  • Count britishMappings.length

Normalize those into this internal shape:

{
  "invisibles": 0,
  "punctuation": 0,
  "homoglyphs": 0,
  "dialect_substitutions": 0
}

Termination with Slop or Not Pro

English (L is en): AI score <= AITHRESHOLD AND the reading-level grade test passes, or after MAXITER. The grade test depends on how the Graduate target was set. For elementary through college, the test is always |grade - targetgrade| <= 1. For the Graduate band: when Graduate was selected as a band (via level=graduate or the interview, with targetgrade derived as 17), replace the grade test with range membership grade >= 15 (the FK lower edge), so a College-level grade of 14 cannot satisfy a Graduate target; when an explicit inline grade=N was given (English only), keep the symmetric |grade - target_grade| <= 1 tolerance regardless of the derived band, so the explicit target is honored. This conditional applies only to English FK; German Wiener level=graduate always uses range membership (no explicit numeric grade there). On non-convergence, return the best iteration: lowest score that meets the grade test; if none meet the grade test, lowest score outright. Do not select an iteration that dropped a source fact or section to lower the score; the Preserve coverage rule above governs the final choice.

Supported non-English (L in {es, de, it, sv, da, nb}): no AI threshold (the AI score is n/a). Terminate when the readability score for L's formula lands in the target band (grade scales use |score - bandmidpoint| <= 1, except the open-ended Graduate band, which uses range membership so a College-level score cannot satisfy a Graduate target; ease scales and LIX use band-range membership; see references/multilingual.md) or after MAXITER. On non-convergence, return the iteration closest to the target band.

Nynorsk (L is nn): tells-only, no readability and no AI score. Run all MAX_ITER iterations and select by quality, as in Core mode.

Unsupported language (L is other): tells-only with no AI score. Run all MAXITER iterations and select by quality, as in Core mode. If analyzereadability returns a known score, log it as advisory only; never terminate or select the final iteration based on that advisory score.

After selecting the final iteration, run Text Cleanup on that selected text. Store finalcleanupstats and use the cleaned text as the final output. Then run the final scoring pass gated by L, matching the loop's per-language rule: for English, run final detecttext and analyzereadability; for supported non-English (es, de, it, sv, da, nb), run final analyzereadability only (skip detecttext, which returns notenglish with a null score); for Nynorsk, skip both; for an unsupported language, run final analyzereadability only and log any known score as advisory (the AI score is n/a).

Completion in Core mode

Run all five rewrite strategies once unless the source is empty or unusable. Log AI score and readability as null for every iteration. Select the final iteration by rewrite quality: preserve meaning and the source's fact and section coverage, honor the requested reading level, tone, and length, and remove the most visible AI tells from the tell files loaded for L's branch (for English, references/patterns.md plus references/supplemental-ai-tells.md; for a supported non-English language, references/supplemental-ai-tells.md plus references/ai-tells/<L>.md, where Norwegian Bokmal and Nynorsk both use references/ai-tells/no.md; for an unsupported language, references/supplemental-ai-tells.md alone, since no per-language tell file exists).

Mid-flight Pro-gate

If any detecttext, analyzereadability, or clean_text call returns isError: true (MCP) or non-zero exit (CLI) on iteration >= 1, fall through to Core mode for the remaining iterations. See references/per-iteration-strategies.md Mid-flight Pro-gate fallback.

Step 7: Output

Render this canonical block. The example shows English; the Language line and the readability column adapt to the resolved language (see the rules below the block).

## Humanized text
<final text>

## Language
English (en-US). Readability: Flesch-Kincaid grade.

## Loop history
| Iter | AI score | Readability | Strategy |
|---|---:|---:|---|
| 0 | 92% | 11.4 (College) | baseline |
| 1 | 71% | 10.8 (High school) | pattern surgery |
| 2 | 48% | 10.4 (High school) | variant + tone |
| 3 | 27% | 9.7 (High school) | grade gap |
Converged at iter 3 (<=40% AI, grade target 9 to 11).

## Text Cleanup summary
| Stage | Invisibles | Punctuation | Homoglyphs | Dialect substitutions |
|---|---:|---:|---:|---:|
| Source cleanup | 1 | 2 | 0 | 0 |
| Final cleanup | 0 | 1 | 0 | 0 |

## Highest-impact edits
- <bullet 1>
- <bullet 2>
- <bullet 3 (optional)>

Language line. Always show the resolved language and variant, plus the readability formula's display name from references/multilingual.md, for example "German (de-DE). Readability: Wiener Sachtextformel." For Norwegian Nynorsk (nn), render readability as unavailable, for example "Norwegian Nynorsk (nn). Readability: not available." For an unsupported language, render readability as advisory when analyze_readability returned a known kind, for example "French (fr-CA). Readability: advisory Flesch-Szigriszt."; otherwise render it as not available. When detection overrode a saved profile language, mark it and add the note, for example "German (de-DE, detected; saved profile language is English). Readability: Wiener Sachtextformel." followed by:

> _Ran in German because the text was detected as German; your saved profile language is English. Override with `language=` to change._

When an inline language= or variant-inferred language overrode a saved profile language, mark that source instead of saying detection chose the language. Use the wording from references/profile-resolution.md, for example:

> _Ran in French because `language=fr` was set for this call; your saved profile language is English._

Readability column. The formula is named once in the Language line (use its display name from references/multilingual.md). In the loop-history column show only the value and the band in parentheses, for example "10.6 (High school)". For unsupported-language advisory readability, show only the value and "(advisory)", since there is no target band.

AI score column (non-English). Render "n/a (detector is English-only)" on the first row and "n/a" thereafter. In Core mode, render "n/a" for every row.

Convergence line (non-English with readability). Reference the band, not the AI threshold, for example "Converged at iter 3 (readability in target band: High school)." For Nynorsk, or an unsupported language with no advisory readability score, use "Completed MAXITER iterations (no readability available for this language; selected by quality)." For an unsupported language with an advisory readability score, use "Completed MAXITER iterations (readability advisory only for this language; selected by quality)."

Show Text Cleanup summary only when real Slop or Not Text Cleanup ran. Do not show backend names in the user-facing output.

If every cleanup count is zero, replace the table with:

## Text Cleanup summary
Slop or Not found no hidden characters, punctuation artifacts, homoglyphs, or dialect substitutions to clean.

When Slop or Not Pro does not converge (English), replace the convergence line with:

Did not converge below threshold in MAX_ITER iterations. Best result shown above
(iter N at S%). Re-run with `threshold=40 max=8` for a more aggressive loop,
or `tone=casual` if professional tone is constraining the rewrite.

For non-English non-convergence, replace the convergence line with:

Did not reach the target band in MAX_ITER iterations. Closest result shown above (iter N, <formula>: X.X). Re-run with a different `level=` to widen the target.

When Slop or Not Pro is unavailable, render score and grade as n/a and add this note after the history table:

> _Ran without Slop or Not Pro. Add Slop or Not Pro for on-device AI detector scoring, readability checks, Text Cleanup, and cleanup stats: <https://slopornot.ai/download>_

For mid-flight Core-mode fallback iterations, render score and grade as n/a and add this note:

> _Iterations N-M ran without on-device scoring. Local stats are unavailable for those iterations._

If voice matching was active, add this footer note:

> _Voice matched from <path> (fingerprint cached <date>)._

If voice extraction failed in Step 4, add this footer note instead:

> _Voice extraction failed; ran without voice match. Re-run with `/agentic-humanizer reset voice` to retry._

Pointer files

  • harnesses/claude-code.md · harnesses/codex.md · harnesses/cursor.md

· harnesses/gemini-cli.md · harnesses/opencode.md · harnesses/generic.md

  • references/patterns.md (the canonical 33 AI tells, English only)
  • references/detection-guidance.md (English-only false-positive guard: what

not to flag, human-writing signals to preserve)

  • references/supplemental-ai-tells.md (supplemental language-agnostic AI tells)
  • references/multilingual.md (the multilingual readability registry)
  • references/profile-resolution.md (the saved-profile vs detected-language

decision table for Step 3)

  • references/ai-tells/<code>.md (per-language tells: es, de, it, sv, da, no)
  • references/per-iteration-strategies.md (the loop cookbook)
  • references/voice-fingerprint.md (voice sample extraction and loop

injection contracts)

  • references/slop-cli-setup.md · references/slop-mcp-setup.md

(install guides; surface to user when they ask for on-device AI detector scoring setup)