Skip to content

devswha/patina

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

770 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

patina mark

patina

Strip the AI packaging. Keep the meaning.

한국어 · 中文 · 日本語 · English

Tests License: MIT Skill: Claude Code | Codex | Cursor | OpenCode Languages: KO | EN | ZH | JA Version 6.3.1

Try it in the browser — no install

Live screen capture of the hosted patina playground at patina.vibetip.help: an AI-sounding English announcement is typed in, rewritten naturally by the real server-side pipeline while the facts survive, and verified with MPS 100 and Fidelity 75 plus a deterministic AI-signal drop from 100 to 0

Paste AI-sounding text → patina rewrites it in place, keeps the facts (the "30 templates" number survives), and drops the deterministic AI signal 100 → 0 (MPS 100 / Fidelity 75).

The words are not the tell. The architecture is. We ran a pre-registered study with independent cross-family LLM judges: a rewrite can strip the AI vocabulary, yet judges still recognize AI documents by their shape — uniform paragraphs, checklist-complete coverage, the tidy problem→lesson arc. Word-level cleanup moved judged AI-likeness a lot on English documents (−23 points) and barely at all on long Korean ones. That result decides patina's design: detect both layers, and publish the losses next to the wins (the study).

patina is a deterministic, pattern-based humanizer for Korean, English, Chinese, and Japanese. It finds AI-sounding phrasing and rewrites it without changing the claim, numbers, polarity, or causation. It is not a black-box paraphraser, authorship detector, or detector-bypass tool — it is built for allowed AI-assisted drafting where the author wants cleaner voice, an audit trail, and meaning-preservation checks.

More examples: Before/After Gallery (한국어) · CLI transcript.

Quick Start

Browser playground

Open patina.vibetip.help — paste KO / EN / ZH / JA text for a real rewrite gated by the MPS/fidelity floors, with the deterministic AI signal measured before → after. Rewrites and scoring run server-side; the free tier uses the service's own model key (rate-limited). API mode forwards your own key per request through the patina server to the provider you pick — never stored or logged (metrics are sanitized: no text, prompt, output, key, or IP). A hosted Pro tier unlocks higher limits — see pricing.

Agent skill

Let your coding agent install it — paste this into Claude Code, Codex CLI, Cursor, Gemini CLI, or any agent:

Install patina by following https://raw.githubusercontent.com/devswha/patina/main/INSTALLATION.md

The agent fetches INSTALLATION.md (written for AI agents) and runs the right install path for your host, then verifies it. Or do it yourself:

Claude Code — plugin marketplace (no clone, recommended):

/plugin marketplace add devswha/patina
/plugin install patina@patina

Claude Code · Codex CLI · Cursor · OpenCode — install script:

curl -fsSL https://raw.githubusercontent.com/devswha/patina/main/install.sh | bash

Then run the skill from Claude Code, Codex CLI, Cursor, or OpenCode:

/patina --lang en

[paste your text here]

Useful skill calls:

/patina --tone professional
/patina --tone auto --lang en

Standalone CLI

Requires Node.js >= 18.

npx patina-cli doctor
npx patina-cli --lang en input.txt

Use a logged-in local model CLI without an API key:

printf '%s\n' 'Coffee has emerged as a pivotal cultural phenomenon.' \
  | npx patina-cli --lang en --backend codex-cli

Supported local backends: codex-cli, claude-cli, gemini-cli, kimi-cli — patina passes the strongest documented default model per backend. See Authentication (한국어).

For large --batch runs, prefer an OpenAI-compatible HTTP backend; local CLI backends are agent runtimes, capped conservatively with --timeout-ms, --max-concurrency, --max-retries, and --max-failures for batch safety.

What You Get

172 patterns 34 rewrite-capable + 9 score-only viral-hook per language (43 each across KO/EN/ZH/JA) — see the full 172-pattern catalog in PATTERNS.md
Modes rewrite · verify · audit · score · diff
Surfaces agent skill · Node CLI · in-place preview · browser playground (rewrite + score)
Voice --persona (built-in + your own, ko/en/zh/ja) is the sole voice axis · --tone register · --profile pattern policy — composable with a fixed precedence
Free usage logged-in codex, claude, or gemini CLI can run rewrites without PATINA_API_KEY
Calibration 67.3% editing-hotspot catch [63.5–71.0%] across GPT-5.5 / Claude Sonnet 4.6 / Gemini 2.5 Pro (n=600, KO+EN); 16.0% false positives [11.6–21.7%] on KO+EN human controls (n=200)
License MIT

Scores are editing signals with false positives and false negatives, not proof of authorship. See Ethics.

Common Commands

patina --lang <ko|en|zh|ja> [mode] [--profile <name>] input.txt
Command Purpose
patina input.txt rewrite with defaults
patina --audit input.txt detect patterns only
patina --score input.txt output a 0-100 AI-likeness score
patina --score --exit-on 30 input.txt CI gate with exit code 3 when overall > 30
patina --diff input.txt show pattern-by-pattern changes
patina --preview page.html render rewrites back onto a saved HTML page with toggles and inline diff
patina --verify input.txt rewrite, then check MPS/fidelity floors with one retry
patina --tone auto --lang en input.txt infer and apply a KO/EN tone axis
patina --persona pragmatic-founder input.txt rewrite in a built-in voice persona
patina persona new my-voice --from-sample past.txt author your own persona from a writing sample
patina persona list list built-in + custom personas
patina persona show my-voice --json print a persona's normalized config (never the docs body)
patina persona edit my-voice --name "New Name" copy-on-edit a persona into custom/personas/
patina persona rm my-voice remove a custom persona (built-ins + preserve protected)
patina --format json --quiet input.txt script-friendly output
patina --batch docs/*.md --outdir cleaned/ batch file processing

patina --help prints the full flag list. patina doctor --json checks Node, backend, tmux, and API-key readiness without making an LLM call.

Personas (voice)

A persona is a reusable voice — a built-in (patina persona list) or your own, authored without editing source:

patina persona new my-voice --from-sample past-posts.txt   # learn from your writing
patina persona new my-voice --describe "plain-spoken founder, casual"
patina --persona my-voice draft.md                          # then reuse it

patina persona show my-voice                                # inspect the normalized config (--json for machine output)
patina persona edit my-voice --name "Founder voice"         # copy-on-edit into custom/personas/ (built-ins stay intact)
patina persona rm my-voice                                  # remove a custom persona (--force to skip the confirm)

Works on ko/en/zh/ja and composes with --tone (register) and --profile (pattern policy). The persona is the sole voice owner; register precedence is --tone > persona. A persona shapes voice but never lowers the meaning floors — authored personas are validated on save, and the safety gate still enforces MPS/fidelity + dropped-number checks.

CI

For GitHub Actions, the maintained wrapper is shorter than hand-rolled setup:

name: Patina prose score
on:
  pull_request:
    paths: ['**/*.md', '**/*.mdx']
permissions:
  contents: read
  pull-requests: read
  issues: write
jobs:
  patina:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: devswha/patina-action@v1
        with:
          score-threshold: 30
          lang: auto
          comment: true

Other integrations: pre-commit, static sites, Docker, release workflow.

How It Works

Input
  -> semantic anchor extraction (claims, polarity, causation, numbers)
  -> stylometry + AI-lexicon scan
  -> pattern-guided rewrite
  -> self-audit and MPS/fidelity checks
  -> cleaned text

If meaning drifts, the change is retried or rolled back. Deterministic analysis lives in src/features/*; LLM-backed rewrite and score calls use the selected backend.

Configuration

# .patina.default.yaml
version: "6.3.1"
language: ko              # ko | en | zh | ja
profile: default
output: rewrite           # rewrite | diff | audit | score
tone:                     # casual | professional | auto  (register; genre = profile)

Project .patina.yaml overrides defaults. Pattern packs are auto-discovered by language prefix. Additive list keys (blocklist, allowlist, skip-patterns) merge; other arrays replace.

Documentation

Start here:

Brand assets and usage rules live in Branding. Design notes live in DESIGN.md.

Acknowledgements

Inspired by oh-my-zsh's plugin architecture, Wikipedia's "Signs of AI writing", and blader/humanizer.

License

MIT. See LICENSE and NOTICE.