patina-cli 3.11.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.patina.default.yaml +29 -29
- package/CHANGELOG.md +53 -0
- package/NOTICE +21 -0
- package/README.md +117 -224
- package/README_JA.md +134 -77
- package/README_KR.md +132 -74
- package/README_ZH.md +137 -80
- package/SKILL.md +11 -20
- package/artifacts/rebaseline-2025/README.md +147 -0
- package/artifacts/rebaseline-2025/human-controls.public.jsonl +250 -0
- package/artifacts/rebaseline-2025/intake.example.jsonl +2 -0
- package/artifacts/rebaseline-2025/intake.local.example.jsonl +25 -0
- package/artifacts/rebaseline-2025/prompts.template.jsonl +7 -0
- package/artifacts/rebaseline-2025/sources.ko-public.jsonl +39 -0
- package/assets/brand/patina-badge.svg +18 -0
- package/assets/brand/patina-mark.svg +8 -0
- package/assets/demo/README.md +79 -0
- package/core/scoring.md +12 -12
- package/core/standalone-prompt.md +3 -1
- package/core/stylometry.md +93 -22
- package/docs/API.md +1554 -0
- package/docs/AUTHENTICATION.md +50 -26
- package/docs/AUTHENTICATION_KR.md +54 -29
- package/docs/BRANDING.md +9 -8
- package/docs/CLI.md +55 -14
- package/docs/COOKBOOK.md +8 -21
- package/docs/DEMO.md +32 -5
- package/docs/EXIT-CODES.md +2 -3
- package/docs/FALSE-POSITIVES.md +63 -0
- package/docs/FAQ.md +9 -1
- package/docs/FAQ_KR.md +3 -1
- package/docs/FLAG-PARITY.md +33 -47
- package/docs/ISSUE-WAVES.md +57 -0
- package/docs/PATTERNS-EN.md +67 -3
- package/docs/PATTERNS-JA.md +68 -2
- package/docs/PATTERNS-KO.md +70 -7
- package/docs/PATTERNS-ZH.md +67 -3
- package/docs/PATTERNS.md +5 -5
- package/docs/RESEARCH-DOCS-PLATFORM.md +54 -0
- package/docs/ROADMAP.md +46 -66
- package/docs/TRANSLATIONESE-KO.md +51 -0
- package/docs/audits/2026-05-deep-research.md +3 -1
- package/docs/benchmarks/README.md +51 -0
- package/docs/benchmarks/detector-comparison.json +69 -9
- package/docs/benchmarks/detector-comparison.md +10 -5
- package/docs/benchmarks/katfish-ko-latest.json +657 -0
- package/docs/benchmarks/katfish-ko-latest.md +77 -0
- package/docs/benchmarks/latest.json +1183 -108
- package/docs/benchmarks/latest.md +84 -60
- package/docs/benchmarks/lexicon-freshness-en-2026-05-22.json +1121 -0
- package/docs/benchmarks/lexicon-freshness-en-2026-05-22.md +136 -0
- package/docs/benchmarks/rebaseline-latest.json +381 -0
- package/docs/benchmarks/rebaseline-latest.md +121 -0
- package/docs/benchmarks/register-stratified-latest.json +164 -0
- package/docs/benchmarks/register-stratified-latest.md +99 -0
- package/docs/benchmarks/register-stratified.md +43 -0
- package/docs/integrations/github-action.md +44 -11
- package/docs/integrations/playground.md +58 -0
- package/docs/integrations/pre-commit.md +5 -5
- package/docs/integrations/release.md +5 -3
- package/docs/integrations/static-sites.md +83 -0
- package/docs/research/2025-rebaseline-plan.md +71 -2
- package/docs/research/2026-rebaseline.md +102 -0
- package/docs/research/adversarial-mps.md +41 -0
- package/docs/research/ai-human-metrics.md +35 -23
- package/docs/research/human-eval-panel.md +42 -0
- package/docs/research/judge-agreement.md +24 -0
- package/docs/research/ko-2025-corpus-sources.md +135 -0
- package/docs/research/lexicon-freshness-audit.md +64 -0
- package/docs/research/zh-ja-lexicon-calibration.md +60 -0
- package/docs/social/patina-launch-copy.md +173 -100
- package/docs/social/patina-launch-execution.md +94 -0
- package/docs/social/patina-launch-korean-first.md +83 -0
- package/docs/social/signs-of-ai-writing.md +26 -0
- package/docs/social/signs-of-ai-writing_KR.md +26 -0
- package/lexicon/ai-en.md +21 -24
- package/lexicon/ai-ja.md +158 -0
- package/lexicon/ai-ko.md +9 -9
- package/lexicon/ai-zh.md +158 -0
- package/lexicon/provenance/ai-en.json +970 -0
- package/lexicon/provenance/ai-ja.json +542 -0
- package/lexicon/provenance/ai-ko.json +866 -0
- package/lexicon/provenance/ai-zh.json +542 -0
- package/package.json +49 -8
- package/patterns/en-communication.md +5 -0
- package/patterns/en-content.md +5 -0
- package/patterns/en-filler.md +5 -0
- package/patterns/en-language.md +29 -1
- package/patterns/en-structure.md +5 -0
- package/patterns/en-style.md +5 -0
- package/patterns/en-viral-hook.md +42 -2
- package/patterns/ja-communication.md +5 -0
- package/patterns/ja-content.md +5 -0
- package/patterns/ja-filler.md +5 -0
- package/patterns/ja-language.md +33 -1
- package/patterns/ja-structure.md +12 -0
- package/patterns/ja-style.md +5 -0
- package/patterns/ja-viral-hook.md +41 -2
- package/patterns/ko-communication.md +5 -0
- package/patterns/ko-content.md +5 -0
- package/patterns/ko-filler.md +5 -0
- package/patterns/ko-language.md +33 -1
- package/patterns/ko-structure.md +25 -6
- package/patterns/ko-style.md +5 -0
- package/patterns/ko-viral-hook.md +38 -2
- package/patterns/zh-communication.md +5 -0
- package/patterns/zh-content.md +5 -0
- package/patterns/zh-filler.md +5 -0
- package/patterns/zh-language.md +37 -1
- package/patterns/zh-structure.md +12 -0
- package/patterns/zh-style.md +5 -0
- package/patterns/zh-viral-hook.md +38 -2
- package/playground/README.md +55 -0
- package/playground/analytics.js +4 -0
- package/playground/analyzer.js +883 -0
- package/playground/app.js +157 -0
- package/playground/data/lexicons.js +343 -0
- package/playground/index.html +138 -0
- package/playground/styles.css +267 -0
- package/profiles/namuwiki.md +111 -0
- package/scripts/adversarial-mps-report.mjs +201 -0
- package/scripts/badge-json.mjs +79 -0
- package/scripts/benchmark-report.mjs +56 -9
- package/scripts/check-release-metadata.mjs +0 -2
- package/scripts/detector-comparison.mjs +7 -7
- package/scripts/generate-playground-data.mjs +77 -0
- package/scripts/katfish-calibration.mjs +464 -0
- package/scripts/lexicon-freshness.mjs +485 -0
- package/scripts/lint.mjs +1 -1
- package/scripts/precommit-score.mjs +4 -3
- package/scripts/prose-score.mjs +81 -5
- package/scripts/rebaseline-intake.mjs +242 -0
- package/scripts/rebaseline-score.mjs +268 -0
- package/scripts/rebaseline-summary.mjs +773 -0
- package/scripts/rebaseline-web-collect.mjs +410 -0
- package/scripts/update-benchmark-ranges.mjs +1 -0
- package/src/api.js +69 -105
- package/src/auth.js +50 -2
- package/src/backends/claude-cli.js +19 -4
- package/src/backends/codex-cli.js +19 -3
- package/src/backends/contract.js +230 -1
- package/src/backends/gemini-cli.js +18 -5
- package/src/backends/index.js +87 -12
- package/src/backends/kimi-cli.js +161 -0
- package/src/cli.js +577 -567
- package/src/commands/doctor.js +2 -2
- package/src/config.js +29 -0
- package/src/errors.js +53 -1
- package/src/features/discourse-tells.js +68 -0
- package/src/features/index.js +82 -8
- package/src/features/lexicon.js +40 -6
- package/src/features/markup-leakage.js +69 -0
- package/src/features/segment.js +41 -0
- package/src/features/signal-strength.js +81 -0
- package/src/features/stylometry.js +231 -1
- package/src/features/translationese.js +127 -0
- package/src/loader.js +76 -0
- package/src/logger.js +22 -23
- package/src/model-defaults.js +55 -0
- package/src/ouroboros.js +31 -0
- package/src/output.js +102 -90
- package/src/prompt-builder.js +103 -68
- package/src/providers.js +51 -4
- package/src/scoring.js +210 -2
- package/src/security.js +75 -0
- package/tests/fixtures/live-quality/en/public-docs-01.md +26 -0
- package/tests/fixtures/live-quality/ko/public-docs-01.md +26 -0
- package/tests/fixtures/suspect-zones/expected-ranges.json +207 -16
- package/tests/fixtures/suspect-zones/ja/ai/ja-ai-04-lexicon.md +11 -0
- package/tests/fixtures/suspect-zones/ja/natural/ja-nat-04-lexicon-cold.md +11 -0
- package/tests/fixtures/suspect-zones/ko/ai/ko-ai-02.md +4 -5
- package/tests/fixtures/suspect-zones/ko/ai/ko-ai-07-ko-diagnostic.md +11 -0
- package/tests/fixtures/suspect-zones/zh/ai/zh-ai-04-lexicon.md +11 -0
- package/tests/fixtures/suspect-zones/zh/natural/zh-nat-04-lexicon-cold.md +11 -0
- package/tests/quality/README.md +188 -11
- package/tests/quality/adversarial-mps/fixtures.jsonl +10 -0
- package/tests/quality/benchmark.mjs +39 -1
- package/tests/quality/dogfood.mjs +5 -3
- package/tests/quality/live-fixtures.jsonl +2 -0
- package/tests/quality/live-quality.mjs +596 -0
- package/tests/quality/ranking-metrics.mjs +136 -0
- package/tests/quality/rebaseline-manifest.example.jsonl +5 -0
- package/vercel.json +53 -0
- package/SKILL-MAX.md +0 -455
- package/docs/internal/HARNESS.md +0 -14
- package/docs/internal/README.md +0 -14
- package/docs/internal/WARP.md +0 -23
- package/patina-max/SKILL.md +0 -523
- package/patina-max/composite.py +0 -457
- package/src/cache.js +0 -106
- package/src/commands/init.js +0 -208
- package/src/manifest.js +0 -162
- package/src/max-mode.js +0 -207
package/docs/AUTHENTICATION.md
CHANGED
|
@@ -7,48 +7,54 @@ patina runs through one of several backends. Pick whichever matches your existin
|
|
|
7
7
|
| Backend | Setup | Cost |
|
|
8
8
|
|---------|-------|------|
|
|
9
9
|
| `codex-cli` | `codex login` | **Free** (ChatGPT OAuth) |
|
|
10
|
-
| `claude-cli` | `claude` (one-time interactive OAuth) | **Free** (Claude subscription) |
|
|
10
|
+
| `claude-cli` | `claude auth login` (one-time interactive OAuth) | **Free** (Claude subscription) |
|
|
11
11
|
| `gemini-cli` | `gemini` (one-time interactive OAuth) or `GEMINI_API_KEY=...` | **Free** (Code Assist OAuth or AI Studio) |
|
|
12
|
+
| `kimi-cli` | `kimi login` (one-time browser OAuth) or `KIMI_API_KEY=...` | Kimi account / Moonshot API |
|
|
12
13
|
| OpenAI-compatible HTTP | `PATINA_API_KEY=...` | Per provider |
|
|
13
14
|
| Google Gemini (HTTP) | `GEMINI_API_KEY=...` + `--provider gemini` | Free tier |
|
|
14
15
|
| Groq | `GROQ_API_KEY=...` + `--provider groq` | Free tier |
|
|
16
|
+
| Kimi / Moonshot (HTTP) | `KIMI_API_KEY=...` + `--provider kimi`, or `MOONSHOT_API_KEY=...` + `--provider moonshot` | Per provider |
|
|
15
17
|
| Together AI | `TOGETHER_API_KEY=...` + `--provider together` | Free models available |
|
|
16
18
|
| OpenRouter | `--base-url https://openrouter.ai/api/v1` + key | Per provider (mix any provider) |
|
|
17
19
|
|
|
18
20
|
```bash
|
|
19
21
|
patina auth status # backend availability + auth state
|
|
20
22
|
patina auth login # per-backend login instructions
|
|
21
|
-
patina
|
|
23
|
+
patina auth login codex-cli # confirm, then run `codex login`
|
|
24
|
+
patina --list-backends # backend selectors + auth state
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
Backend selection requires an explicit signal: pass `--backend <name>` directly, pass a comma-separated fallback chain such as `--backend claude-cli,codex-cli`, or use `--model <prefix>` (`codex-*`, `claude-*`, `gemini-*` route to the matching local CLI). With no flags and no API key, patina exits with an error rather than silently dispatching to a coding agent. See [issue #88](https://github.com/devswha/patina/issues/88) for the rationale.
|
|
27
|
+
Backend selection requires an explicit signal: pass `--backend <name>` directly, pass a comma-separated fallback chain such as `--backend claude-cli,codex-cli`, or use `--model <prefix>` (`codex-*`, `claude-*`, `gemini-*`, `kimi-*` route to the matching local CLI). With no flags and no API key, patina exits with an error rather than silently dispatching to a coding agent. See [issue #88](https://github.com/devswha/patina/issues/88) for the rationale.
|
|
25
28
|
|
|
26
29
|
## Environment variables
|
|
27
30
|
|
|
28
31
|
```bash
|
|
29
32
|
PATINA_API_KEY=... # required for HTTP backend
|
|
30
33
|
PATINA_API_BASE=https://api.openai.com/v1 # or proxy / OpenRouter / etc.
|
|
31
|
-
PATINA_MODEL=gpt-
|
|
34
|
+
PATINA_MODEL=gpt-5.5 # HTTP/OpenAI default model
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
`--base-url`, `--model`, `--api-key`, `--provider` flags override these per run.
|
|
37
|
+
`--base-url`, `--model`, `--api-key-file`, and `--provider` flags override these per run.
|
|
38
|
+
When you do not pass `--model`, patina uses its strongest documented default per backend: `gpt-5.5` for OpenAI HTTP and `codex-cli`, `claude-sonnet-4-6` for `claude-cli`, `gemini-2.5-pro` for Gemini HTTP/CLI, `kimi-code/kimi-for-coding` for `kimi-cli`, and `kimi-k2.5` for Kimi/Moonshot HTTP. Exact selector aliases such as `--model codex`, `--model claude`, `--model gemini`, and `--model kimi` still route to the local CLI while using that backend default.
|
|
35
39
|
|
|
36
40
|
## codex-cli backend
|
|
37
41
|
|
|
38
|
-
patina dispatches via the local [`codex`](https://github.com/openai/codex) CLI, which authenticates via OpenAI/ChatGPT OAuth — no API key needed.
|
|
42
|
+
patina dispatches via the local [`codex`](https://github.com/openai/codex) CLI, which authenticates via OpenAI/ChatGPT OAuth — no API key needed. The default model passed to `codex exec` is `gpt-5.5` unless you provide a more specific Codex model id.
|
|
39
43
|
|
|
40
44
|
```bash
|
|
41
45
|
codex login # one-time
|
|
46
|
+
patina auth login codex-cli # same, with confirmation
|
|
42
47
|
patina --backend codex-cli --lang ko input.txt
|
|
43
|
-
patina --model codex --lang ko input.txt #
|
|
48
|
+
patina --model codex --lang ko input.txt # routes to codex-cli, uses gpt-5.5 default
|
|
44
49
|
```
|
|
45
50
|
|
|
46
51
|
## claude-cli backend
|
|
47
52
|
|
|
48
|
-
Spawns local [`claude`](https://docs.anthropic.com/en/docs/claude-code) `-p` with the patina prompt on stdin. Free for anyone with a Claude subscription.
|
|
53
|
+
Spawns local [`claude`](https://docs.anthropic.com/en/docs/claude-code) `-p` with the patina prompt on stdin. Free for anyone with a Claude subscription. Claude Code is an agent runtime, so patina treats it conservatively in batch mode: compact prompt mode, default max concurrency `1`, and default retries `0`. The default model passed to Claude Code is `claude-sonnet-4-6`; Claude Code may still apply its own model/session policy outside patina's control.
|
|
49
54
|
|
|
50
55
|
```bash
|
|
51
|
-
claude
|
|
56
|
+
claude auth login # one-time interactive OAuth
|
|
57
|
+
patina auth login claude-cli # same, with confirmation
|
|
52
58
|
patina --backend claude-cli --lang ko input.txt
|
|
53
59
|
patina --model claude-sonnet-4-6 --lang ko input.txt # auto-routes
|
|
54
60
|
```
|
|
@@ -57,22 +63,46 @@ Auth file: `~/.claude/.credentials.json` (created by the OAuth flow).
|
|
|
57
63
|
|
|
58
64
|
## gemini-cli backend
|
|
59
65
|
|
|
60
|
-
Spawns local [`gemini`](https://github.com/google-gemini/gemini-cli) `-p '' --output-format text` with the patina prompt on stdin. Works with the free Code Assist OAuth tier or with `GEMINI_API_KEY`.
|
|
66
|
+
Spawns local [`gemini`](https://github.com/google-gemini/gemini-cli) `-p '' --output-format text` with the patina prompt on stdin. Works with the free Code Assist OAuth tier or with `GEMINI_API_KEY`. The default model is `gemini-2.5-pro`.
|
|
61
67
|
|
|
62
68
|
```bash
|
|
63
69
|
gemini # one-time interactive OAuth, OR
|
|
70
|
+
patina auth login gemini-cli # same, with confirmation
|
|
64
71
|
export GEMINI_API_KEY="..." # AI Studio key
|
|
65
72
|
patina --backend gemini-cli --lang ko input.txt
|
|
66
73
|
patina --model gemini-3-flash-preview --lang ko input.txt # auto-routes
|
|
67
74
|
```
|
|
68
75
|
|
|
76
|
+
## kimi-cli backend
|
|
77
|
+
|
|
78
|
+
Spawns local [`kimi`](https://moonshotai.github.io/kimi-cli/) in print mode with the patina prompt on stdin. It works with Kimi Code CLI browser login, `KIMI_API_KEY`, or `MOONSHOT_API_KEY`. Kimi Code is an agent runtime, so patina treats it conservatively in batch mode: compact prompt mode, default max concurrency `1`, and default retries `0`. The default local CLI model is `kimi-code/kimi-for-coding`; the CLI display name may differ from Moonshot HTTP model IDs.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
kimi login # one-time browser OAuth, OR
|
|
82
|
+
patina auth login kimi-cli # same, with confirmation
|
|
83
|
+
export KIMI_API_KEY="..." # optional API key path
|
|
84
|
+
patina --backend kimi-cli --lang ko input.txt
|
|
85
|
+
patina --model kimi --lang ko input.txt # routes to kimi-cli, uses backend default
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use `--yes` only for automation where the launch is already intentional:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
patina auth login codex-cli --yes
|
|
92
|
+
```
|
|
93
|
+
|
|
69
94
|
Notes: patina passes `--skip-trust` because the prompt runs from a fresh temp directory (containment for prompt-injection in user text). Default timeout is higher than other CLIs because gemini's startup latency is longer.
|
|
70
95
|
|
|
71
|
-
> **
|
|
96
|
+
> **Mode support:** `codex-cli`, `claude-cli`, `gemini-cli`, and `kimi-cli` can be used as rewrite backends without `PATINA_API_KEY` when their local CLIs are already authenticated. API-backed score/audit paths still use the configured HTTP/evaluator key.
|
|
72
97
|
|
|
73
|
-
|
|
98
|
+
For large rewrite batches, prefer `openai-http` or another stateless
|
|
99
|
+
OpenAI-compatible HTTP provider over local agent CLIs. Batch mode exposes
|
|
100
|
+
`--timeout-ms`, `--max-concurrency`, `--max-retries`, `--max-failures`,
|
|
101
|
+
`--max-failure-rate`, and `--stop-on-retryable-storm`; see [CLI.md](CLI.md#batch-safety-controls).
|
|
74
102
|
|
|
75
|
-
|
|
103
|
+
## HTTP provider examples
|
|
104
|
+
|
|
105
|
+
Get an API key from the provider you want to call:
|
|
76
106
|
|
|
77
107
|
```bash
|
|
78
108
|
# Google Gemini — https://aistudio.google.com/app/apikey
|
|
@@ -86,20 +116,14 @@ patina --provider groq --lang ko input.txt
|
|
|
86
116
|
# Together AI (free models suffixed with "-Free")
|
|
87
117
|
export TOGETHER_API_KEY="..."
|
|
88
118
|
patina --provider together --lang ko input.txt
|
|
89
|
-
```
|
|
90
119
|
|
|
91
|
-
|
|
120
|
+
# Kimi / Moonshot (paid API)
|
|
121
|
+
export KIMI_API_KEY="..."
|
|
122
|
+
patina --provider kimi --lang ko input.txt
|
|
92
123
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
| Model | Dispatch | Auth |
|
|
98
|
-
|-------|----------|------|
|
|
99
|
-
| `claude` | `claude -p` | Claude Code |
|
|
100
|
-
| `codex` | `codex exec --skip-git-repo-check --output-last-message` | ChatGPT OAuth |
|
|
101
|
-
| `gemini` | `gemini -p '' --output-format text` | Google AI Studio |
|
|
124
|
+
export MOONSHOT_API_KEY="..."
|
|
125
|
+
patina --provider moonshot --lang ko input.txt
|
|
126
|
+
```
|
|
102
127
|
|
|
103
|
-
|
|
128
|
+
`--provider` sets the right base URL, default model, and reads the provider-specific API key env var. Override these with `--base-url`, `--model`, or `--api-key-file`.
|
|
104
129
|
|
|
105
|
-
The standalone CLI MAX (`patina --models <list>`) calls models via the same `--base-url` endpoint, so all listed models must be served by that endpoint. To mix providers (OpenAI + Anthropic + Google), point `--base-url` at OpenRouter or another multi-provider gateway.
|
|
@@ -1,78 +1,109 @@
|
|
|
1
1
|
# 인증과 백엔드
|
|
2
2
|
|
|
3
|
-
patina는 여러
|
|
3
|
+
patina는 여러 백엔드 가운데 하나로 실행됩니다. 지금 쓰는 도구와 인증 방식에 맞춰 고르면 됩니다.
|
|
4
4
|
|
|
5
5
|
## Backend matrix
|
|
6
6
|
|
|
7
7
|
| Backend | Setup | Cost |
|
|
8
8
|
|---------|-------|------|
|
|
9
9
|
| `codex-cli` | `codex login` | **Free** (ChatGPT OAuth) |
|
|
10
|
-
| `claude-cli` | `claude` (one-time interactive OAuth) | **Free** (Claude subscription) |
|
|
10
|
+
| `claude-cli` | `claude auth login` (one-time interactive OAuth) | **Free** (Claude subscription) |
|
|
11
11
|
| `gemini-cli` | `gemini` (one-time interactive OAuth) or `GEMINI_API_KEY=...` | **Free** (Code Assist OAuth or AI Studio) |
|
|
12
|
+
| `kimi-cli` | `kimi login` (one-time browser OAuth) or `KIMI_API_KEY=...` | Kimi account / Moonshot API |
|
|
12
13
|
| OpenAI-compatible HTTP | `PATINA_API_KEY=...` | Per provider |
|
|
13
14
|
| Google Gemini (HTTP) | `GEMINI_API_KEY=...` + `--provider gemini` | Free tier |
|
|
14
15
|
| Groq | `GROQ_API_KEY=...` + `--provider groq` | Free tier |
|
|
16
|
+
| Kimi / Moonshot (HTTP) | `KIMI_API_KEY=...` + `--provider kimi`, 또는 `MOONSHOT_API_KEY=...` + `--provider moonshot` | Per provider |
|
|
15
17
|
| Together AI | `TOGETHER_API_KEY=...` + `--provider together` | Free models available |
|
|
16
18
|
| OpenRouter | `--base-url https://openrouter.ai/api/v1` + key | Per provider (mix any provider) |
|
|
17
19
|
|
|
18
20
|
```bash
|
|
19
21
|
patina auth status # backend availability + auth state
|
|
20
22
|
patina auth login # per-backend login instructions
|
|
21
|
-
patina
|
|
23
|
+
patina auth login codex-cli # confirm 후 `codex login` 실행
|
|
24
|
+
patina --list-backends # backend selector와 auth 상태
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
백엔드는 명시적으로 골라야 합니다. `--backend <name>`을 직접 넘기거나, `--backend claude-cli,codex-cli`처럼 우선순위를 적거나, `--model <prefix>`를 쓰세요. `codex-*`, `claude-*`, `gemini-*`, `kimi-*`는 각각 해당 CLI로 연결됩니다. 아무 플래그도 없고 API 키도 없으면 patina는 다른 에이전트로 몰래 넘기지 않고 바로 오류로 끝납니다. 배경은 [issue #88](https://github.com/devswha/patina/issues/88)를 보면 됩니다.
|
|
25
28
|
|
|
26
29
|
## Environment variables
|
|
27
30
|
|
|
28
31
|
```bash
|
|
29
32
|
PATINA_API_KEY=... # required for HTTP backend
|
|
30
33
|
PATINA_API_BASE=https://api.openai.com/v1 # or proxy / OpenRouter / etc.
|
|
31
|
-
PATINA_MODEL=gpt-
|
|
34
|
+
PATINA_MODEL=gpt-5.5 # HTTP/OpenAI default model
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
`--base-url`, `--model`, `--api-key`, `--provider`
|
|
37
|
+
`--base-url`, `--model`, `--api-key-file`, `--provider` 플래그는 그 실행에 한해서 이 값을 덮어씁니다.
|
|
38
|
+
`--model`을 따로 주지 않으면 patina는 백엔드마다 문서에 적어 둔 기본 모델을 씁니다. OpenAI HTTP와 `codex-cli`는 `gpt-5.5`, `claude-cli`는 `claude-sonnet-4-6`, Gemini HTTP/CLI는 `gemini-2.5-pro`, `kimi-cli`는 `kimi-code/kimi-for-coding`, Kimi/Moonshot HTTP는 `kimi-k2.5`입니다. `--model codex`, `--model claude`, `--model gemini`, `--model kimi` 같은 별칭도 각 CLI로 라우팅되지만 실제로 넘기는 값은 그 백엔드의 기본 모델입니다.
|
|
35
39
|
|
|
36
40
|
## codex-cli backend
|
|
37
41
|
|
|
38
|
-
patina는
|
|
42
|
+
patina는 로컬 [`codex`](https://github.com/openai/codex) CLI로 요청을 보냅니다. 이 CLI는 OpenAI/ChatGPT OAuth로 인증하므로 API 키가 필요 없습니다. `codex exec`에 기본으로 넘기는 모델은 `gpt-5.5`이고, 더 구체적인 Codex 모델 ID를 직접 주면 그 값을 그대로 씁니다.
|
|
39
43
|
|
|
40
44
|
```bash
|
|
41
45
|
codex login # one-time
|
|
46
|
+
patina auth login codex-cli # same, with confirmation
|
|
42
47
|
patina --backend codex-cli --lang ko input.txt
|
|
43
|
-
patina --model codex --lang ko input.txt #
|
|
48
|
+
patina --model codex --lang ko input.txt # codex-cli로 라우팅하고 gpt-5.5 기본값 사용
|
|
44
49
|
```
|
|
45
50
|
|
|
46
51
|
## claude-cli backend
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
로컬 [`claude`](https://docs.anthropic.com/en/docs/claude-code) `-p`에 patina 프롬프트를 stdin으로 넘겨 실행합니다. Claude 구독이 있으면 추가 API 키 없이 쓸 수 있습니다. Claude Code는 agent runtime이므로 batch 모드에서는 보수적으로 다룹니다: compact prompt mode, 기본 동시성 `1`, 기본 retry `0`. 기본 모델은 `claude-sonnet-4-6`이지만, Claude Code 자체의 모델/세션 정책은 patina가 완전히 통제하지 못할 수 있습니다.
|
|
49
54
|
|
|
50
55
|
```bash
|
|
51
|
-
claude
|
|
56
|
+
claude auth login # one-time interactive OAuth
|
|
57
|
+
patina auth login claude-cli # same, with confirmation
|
|
52
58
|
patina --backend claude-cli --lang ko input.txt
|
|
53
59
|
patina --model claude-sonnet-4-6 --lang ko input.txt # auto-routes
|
|
54
60
|
```
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
인증 파일: `~/.claude/.credentials.json` (OAuth 로그인 뒤 생성됩니다).
|
|
57
63
|
|
|
58
64
|
## gemini-cli backend
|
|
59
65
|
|
|
60
|
-
|
|
66
|
+
로컬 [`gemini`](https://github.com/google-gemini/gemini-cli) `-p '' --output-format text`에 patina 프롬프트를 stdin으로 넘겨 실행합니다. 무료 Code Assist OAuth tier나 `GEMINI_API_KEY`로 쓸 수 있고, 기본 모델은 `gemini-2.5-pro`입니다.
|
|
61
67
|
|
|
62
68
|
```bash
|
|
63
69
|
gemini # one-time interactive OAuth, OR
|
|
70
|
+
patina auth login gemini-cli # same, with confirmation
|
|
64
71
|
export GEMINI_API_KEY="..." # AI Studio key
|
|
65
72
|
patina --backend gemini-cli --lang ko input.txt
|
|
66
73
|
patina --model gemini-3-flash-preview --lang ko input.txt # auto-routes
|
|
67
74
|
```
|
|
68
75
|
|
|
69
|
-
|
|
76
|
+
## kimi-cli backend
|
|
70
77
|
|
|
71
|
-
|
|
78
|
+
로컬 [`kimi`](https://moonshotai.github.io/kimi-cli/)를 print mode로 실행하고 patina 프롬프트를 stdin으로 넘깁니다. Kimi Code CLI 브라우저 로그인이나 `KIMI_API_KEY`, `MOONSHOT_API_KEY` 중 하나로 인증할 수 있습니다. Kimi Code는 agent runtime이므로 batch 모드에서는 보수적으로 다룹니다: compact prompt mode, 기본 동시성 `1`, 기본 retry `0`. 로컬 CLI 기본 모델은 `kimi-code/kimi-for-coding`이며, CLI 표시 이름은 Moonshot HTTP 모델 ID와 다를 수 있습니다.
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
```bash
|
|
81
|
+
kimi login # one-time browser OAuth, OR
|
|
82
|
+
patina auth login kimi-cli # same, with confirmation
|
|
83
|
+
export KIMI_API_KEY="..." # optional API key path
|
|
84
|
+
patina --backend kimi-cli --lang ko input.txt
|
|
85
|
+
patina --model kimi --lang ko input.txt # kimi-cli로 라우팅하고 backend 기본값 사용
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
자동화에서는 이미 실행 의도가 분명할 때만 `--yes`를 쓰세요.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
patina auth login codex-cli --yes
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
참고: patina는 사용자 텍스트 안의 prompt injection 영향을 줄이려고 새 임시 디렉터리에서 프롬프트를 실행하고 `--skip-trust`를 함께 넘깁니다. gemini는 시작이 느린 편이라 기본 timeout도 다른 CLI보다 더 길게 잡혀 있습니다.
|
|
74
95
|
|
|
75
|
-
|
|
96
|
+
> **지원 범위:** `codex-cli`, `claude-cli`, `gemini-cli`, `kimi-cli`는 로컬 CLI 로그인만 되어 있으면 `PATINA_API_KEY` 없이 rewrite 백엔드로 쓸 수 있습니다. 반면 API 기반 score/audit 경로는 계속 설정된 HTTP/evaluator 키를 사용합니다.
|
|
97
|
+
|
|
98
|
+
대량 rewrite batch는 가능한 한 로컬 agent CLI보다 `openai-http` 같은 stateless
|
|
99
|
+
OpenAI-compatible HTTP provider를 쓰세요. Batch 모드는 `--timeout-ms`,
|
|
100
|
+
`--max-concurrency`, `--max-retries`, `--max-failures`,
|
|
101
|
+
`--max-failure-rate`, `--stop-on-retryable-storm`을 제공합니다. 자세한 내용은
|
|
102
|
+
[CLI.md](CLI.md#batch-safety-controls)를 보세요.
|
|
103
|
+
|
|
104
|
+
## HTTP provider examples
|
|
105
|
+
|
|
106
|
+
호출할 프로바이더에 맞는 API 키를 준비한 뒤 아래처럼 실행하면 됩니다.
|
|
76
107
|
|
|
77
108
|
```bash
|
|
78
109
|
# Google Gemini — https://aistudio.google.com/app/apikey
|
|
@@ -86,20 +117,14 @@ patina --provider groq --lang ko input.txt
|
|
|
86
117
|
# Together AI (free models suffixed with "-Free")
|
|
87
118
|
export TOGETHER_API_KEY="..."
|
|
88
119
|
patina --provider together --lang ko input.txt
|
|
89
|
-
```
|
|
90
120
|
|
|
91
|
-
|
|
121
|
+
# Kimi / Moonshot (paid API)
|
|
122
|
+
export KIMI_API_KEY="..."
|
|
123
|
+
patina --provider kimi --lang ko input.txt
|
|
92
124
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
| Model | Dispatch | Auth |
|
|
98
|
-
|-------|----------|------|
|
|
99
|
-
| `claude` | `claude -p` | Claude Code |
|
|
100
|
-
| `codex` | `codex exec --skip-git-repo-check --output-last-message` | ChatGPT OAuth |
|
|
101
|
-
| `gemini` | `gemini -p '' --output-format text` | Google AI Studio |
|
|
125
|
+
export MOONSHOT_API_KEY="..."
|
|
126
|
+
patina --provider moonshot --lang ko input.txt
|
|
127
|
+
```
|
|
102
128
|
|
|
103
|
-
|
|
129
|
+
`--provider`를 쓰면 맞는 base URL과 기본 모델이 자동으로 잡히고, 그 프로바이더에 해당하는 API 키 환경변수도 함께 읽습니다. 필요하면 `--base-url`, `--model`, `--api-key-file`로 각각 덮어쓸 수 있습니다.
|
|
104
130
|
|
|
105
|
-
Standalone CLI MAX(`patina --models <list>`)는 같은 `--base-url` endpoint를 통해 모델을 호출하므로, 나열된 모든 모델이 그 endpoint에서 제공되어야 합니다. provider를 섞으려면(OpenAI + Anthropic + Google) `--base-url`을 OpenRouter나 다른 multi-provider gateway로 지정하세요.
|
package/docs/BRANDING.md
CHANGED
|
@@ -6,22 +6,23 @@ Patina's production brand assets are hand-authored SVGs so maintainers can revie
|
|
|
6
6
|
|
|
7
7
|
| Asset | Path | Use |
|
|
8
8
|
|---|---|---|
|
|
9
|
-
| Logo lockup | [`assets/brand/patina-logo.svg`](../assets/brand/patina-logo.svg) |
|
|
10
|
-
|
|
|
9
|
+
| Logo lockup | [`assets/brand/patina-logo.svg`](../assets/brand/patina-logo.svg) | Package pages and docs landing pages that need the full wordmark + tagline |
|
|
10
|
+
| Transparent mark | [`assets/brand/patina-mark.svg`](../assets/brand/patina-mark.svg) | README hero and other places where surrounding text already supplies the project name |
|
|
11
|
+
| App icon | [`assets/brand/patina-icon.svg`](../assets/brand/patina-icon.svg) | Favicon/app tile/avatar contexts that need a dark backplate |
|
|
11
12
|
| Social preview | [`assets/social/patina-og.svg`](../assets/social/patina-og.svg) | Open Graph / social card export source |
|
|
12
13
|
| Before/after card | [`assets/social/patina-before-after.svg`](../assets/social/patina-before-after.svg) | Launch posts and docs examples |
|
|
13
14
|
|
|
14
|
-
`patina-logo.svg` is the single canonical horizontal logo.
|
|
15
|
+
`patina-logo.svg` is the single canonical horizontal logo. README uses the transparent mark plus Markdown heading/tagline to avoid repeating the wordmark and tagline.
|
|
15
16
|
|
|
16
17
|
## Accessibility checklist
|
|
17
18
|
|
|
18
19
|
- Keep `role="img"` on standalone SVG assets.
|
|
19
20
|
- Include `<title>` and `<desc>`, or an `aria-label` when a tiny decorative asset cannot carry children.
|
|
20
21
|
- Keep the square icon recognizable at 32px.
|
|
21
|
-
- Keep the logo on a dark backplate so
|
|
22
|
+
- Keep the app icon and logo lockup on a dark backplate so they work on GitHub light and dark themes. The transparent mark is for layouts that already provide their own page background.
|
|
22
23
|
- Use system font fallbacks in SVG text; GitHub does not load external web fonts inside `<img>` SVGs.
|
|
23
24
|
|
|
24
|
-
## Open Graph setup for
|
|
25
|
+
## Open Graph setup for the playground/docs site
|
|
25
26
|
|
|
26
27
|
Markdown on GitHub cannot set Open Graph tags. If patina gets a docs site, use the checked-in social SVG or a generated PNG export and add:
|
|
27
28
|
|
|
@@ -29,9 +30,9 @@ Markdown on GitHub cannot set Open Graph tags. If patina gets a docs site, use t
|
|
|
29
30
|
<meta property="og:title" content="patina — Strip the AI packaging. Keep the meaning.">
|
|
30
31
|
<meta property="og:description" content="Auditable AI-prose cleanup for KO, EN, ZH, and JA with meaning-preservation checks.">
|
|
31
32
|
<meta property="og:type" content="website">
|
|
32
|
-
<meta property="og:image" content="https://patina.
|
|
33
|
+
<meta property="og:image" content="https://patina.vibetip.help/assets/social/patina-og.svg">
|
|
33
34
|
<meta name="twitter:card" content="summary_large_image">
|
|
34
|
-
<meta name="twitter:image" content="https://patina.
|
|
35
|
+
<meta name="twitter:image" content="https://patina.vibetip.help/assets/social/patina-og.svg">
|
|
35
36
|
```
|
|
36
37
|
|
|
37
|
-
Export note:
|
|
38
|
+
Export note: the playground uses the checked-in SVG directly. If a platform requires PNG, keep the SVG as source and publish a PNG derivative from CI or the docs-site build.
|
package/docs/CLI.md
CHANGED
|
@@ -4,7 +4,7 @@ patina's CLI is optimized for interactive editing, but a few surfaces are stable
|
|
|
4
4
|
|
|
5
5
|
## Score gate
|
|
6
6
|
|
|
7
|
-
Use `--score --exit-on <n>`
|
|
7
|
+
Use `--score --exit-on <n>` when CI should fail if a text still reads too AI-like.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
patina --lang en --score --exit-on 30 draft.md
|
|
@@ -21,8 +21,7 @@ patina --lang en --score --exit-on 30 draft.md
|
|
|
21
21
|
| `0` | Command completed; for `--score --exit-on`, the score was at or below the gate. |
|
|
22
22
|
| `1` | Runtime or backend error, including API/auth/backend failures. |
|
|
23
23
|
| `2` | Input/usage error from no interactive input or empty stdin. |
|
|
24
|
-
| `3` | `--score --exit-on`
|
|
25
|
-
| `4` | MAX mode all candidates failed, or patina fell back because no candidate met the MPS floor. |
|
|
24
|
+
| `3` | `--score --exit-on` completed, but the score exceeded the configured gate. |
|
|
26
25
|
|
|
27
26
|
## Output formats
|
|
28
27
|
|
|
@@ -43,11 +42,9 @@ patina --lang en --score --exit-on 30 draft.md
|
|
|
43
42
|
|
|
44
43
|
- `overall` and `categories[]` are populated when patina can parse them from score JSON or score tables.
|
|
45
44
|
- Score JSON may include `scores.llm`, `scores.deterministic`, and `scores.preference` when deterministic shadow scoring is available.
|
|
46
|
-
- `mps` is populated
|
|
47
|
-
- `gateResult` is `null` unless `--exit-on`
|
|
45
|
+
- `mps` is populated when the underlying mode emits it.
|
|
46
|
+
- `gateResult` is `null` unless `--exit-on` is used.
|
|
48
47
|
- `--voice-sample <path>` or config `voice-sample: <path>` injects the first 1–3 user-written paragraphs into rewrite/Ouroboros prompts as style-only examples of how this person writes. `--profile` / `--tone` still define the outer register; samples refine cadence and texture without importing facts.
|
|
49
|
-
- `--save-run <dir>` writes a schema-v2 `manifest.json` plus `output-N.txt` files for reproducible audit trails. Each result records prompt/response hashes, available token usage, temperature/seed, score details, per-call cost when providers return it, and the Ouroboros iteration log when used.
|
|
50
|
-
- `--cache <dir>` or `PATINA_CACHE_DIR` enables an opt-in persistent HTTP response cache keyed by prompt, model, temperature, and API host. `--cache-ttl <sec>` / `PATINA_CACHE_TTL_SECONDS` set expiry, and `--no-cache` forces a fresh run.
|
|
51
48
|
- `patina doctor --json` emits setup diagnostics for CI without making an LLM call.
|
|
52
49
|
|
|
53
50
|
## Stderr logs
|
|
@@ -55,12 +52,11 @@ patina --lang en --score --exit-on 30 draft.md
|
|
|
55
52
|
Human-facing status, warnings, and progress indicators go to stderr so stdout
|
|
56
53
|
stays reserved for the transformed text or JSON envelope.
|
|
57
54
|
|
|
58
|
-
- `--quiet` suppresses stderr logs, including
|
|
59
|
-
- `--json-logs` emits newline-delimited JSON records with stable fields:
|
|
60
|
-
`ts`, `level`, `event`, `model`, `latency_ms`, and optional `message`.
|
|
61
|
-
- MAX mode (`--models`) reports elapsed per-model status (`...`, `✓`, `✗`).
|
|
55
|
+
- `--quiet` suppresses stderr logs, including Ouroboros progress.
|
|
62
56
|
- Ouroboros reports per-iteration score movement and latency.
|
|
63
57
|
|
|
58
|
+
|
|
59
|
+
|
|
64
60
|
## Backend fallback chains
|
|
65
61
|
|
|
66
62
|
`--backend <name>` selects one backend. `--backend a,b,c` selects an explicit
|
|
@@ -73,8 +69,53 @@ patina --backend claude-cli,codex-cli --lang en draft.md
|
|
|
73
69
|
```
|
|
74
70
|
|
|
75
71
|
All backends share the same invocation contract:
|
|
76
|
-
`invoke({ prompt, model, signal, timeout }): Promise<string>`.
|
|
77
|
-
backends honor `AbortSignal` by killing their child process
|
|
78
|
-
|
|
72
|
+
`invoke({ prompt, model, modelSource, signal, timeout, maxRetries }): Promise<string>`.
|
|
73
|
+
Local CLI backends honor `AbortSignal` by killing their child process. When no
|
|
74
|
+
explicit model is set, local backends pass the strongest documented default to
|
|
75
|
+
their CLI (`gpt-5.5`, `claude-sonnet-4-6`, `gemini-2.5-pro`, or
|
|
76
|
+
`kimi-code/kimi-for-coding`); the HTTP backend bridges the same signal into
|
|
77
|
+
fetch.
|
|
78
|
+
|
|
79
|
+
## Batch safety controls
|
|
80
|
+
|
|
81
|
+
Batch runs print a preflight safety line before the first request: file count,
|
|
82
|
+
backend chain, prompt mode, backend concurrency cap, retry budget, timeout,
|
|
83
|
+
worst-case request count, and largest/average prompt size.
|
|
84
|
+
|
|
85
|
+
Defaults are intentionally conservative:
|
|
86
|
+
|
|
87
|
+
| Backend | Prompt mode | Max concurrency | Max retries |
|
|
88
|
+
|---|---|---:|---:|
|
|
89
|
+
| `openai-http` | strict | 4 | 2 |
|
|
90
|
+
| `codex-cli` | minimal | 2 | 0 |
|
|
91
|
+
| `claude-cli` | minimal | 1 | 0 |
|
|
92
|
+
| `gemini-cli` | minimal | 2 | 0 |
|
|
93
|
+
| `kimi-cli` | minimal | 1 | 0 |
|
|
94
|
+
|
|
95
|
+
Local CLIs are agent runtimes, not stateless completion APIs. For large rewrite
|
|
96
|
+
batches, prefer an OpenAI-compatible HTTP provider. Override the guardrails only
|
|
97
|
+
when you have measured the backend:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
patina --batch --backend openai-http --max-concurrency 4 --max-retries 2 docs/*.md
|
|
101
|
+
patina --batch --backend kimi-cli --max-concurrency 1 --max-retries 0 docs/*.md
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Circuit breakers stop batch mode after repeated failure instead of burning quota:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
patina --batch --max-failures 5 --max-failure-rate 0.25 --stop-on-retryable-storm docs/*.md
|
|
108
|
+
patina --batch --timeout-ms 600000 docs/*.md
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`--max-failure-rate` accepts either a ratio (`0.25`) or a percent (`25`). By
|
|
112
|
+
default, batch mode stops after a small failure budget, after a 25% failure rate
|
|
113
|
+
once enough files have run, or after repeated retryable storms such as HTTP 429,
|
|
114
|
+
timeouts, empty local-CLI responses, or repeated Kimi/Claude process exits.
|
|
115
|
+
|
|
116
|
+
MDX/frontmatter note: patina does not parse MDX or rewrite YAML frontmatter
|
|
117
|
+
schemas. For `.mdx` batches, run your site's MDX/build validator after patina
|
|
118
|
+
and keep project-specific guards for frontmatter quoting, trailing model footers,
|
|
119
|
+
and JSX hazards such as malformed `<digit` fragments.
|
|
79
120
|
|
|
80
121
|
See [EXIT-CODES.md](EXIT-CODES.md) for the full process contract.
|
package/docs/COOKBOOK.md
CHANGED
|
@@ -20,7 +20,7 @@ patina --lang en --score --batch content/posts/*.md
|
|
|
20
20
|
For a stricter sweep that flags anything above 30/100, fail the run instead of just printing:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
patina --lang en --score --
|
|
23
|
+
patina --lang en --score --exit-on 30 --batch content/posts/*.md
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
When any file's `overall` exceeds the gate, patina exits with code `3` ([`CLI.md`](CLI.md) §Exit codes), which is perfect for a pre-publish check.
|
|
@@ -53,40 +53,27 @@ jobs:
|
|
|
53
53
|
run: |
|
|
54
54
|
changed=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- '*.md')
|
|
55
55
|
[ -z "$changed" ] && echo "no markdown changes" && exit 0
|
|
56
|
-
patina --lang en --score --
|
|
56
|
+
patina --lang en --score --exit-on 30 --batch $changed
|
|
57
57
|
env:
|
|
58
58
|
# pick one backend that has a token in repo secrets
|
|
59
59
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
Drop `--
|
|
62
|
+
Drop `--exit-on` while you calibrate the threshold for your project. Swap `GEMINI_API_KEY` for whichever backend you have (`claude` / `codex` / `gemini`) — see [`AUTHENTICATION.md`](AUTHENTICATION.md) for the full list.
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
66
|
-
## 3. Compare Claude vs Gemini output
|
|
66
|
+
## 3. Compare Claude vs Gemini output manually
|
|
67
67
|
|
|
68
|
-
When you want
|
|
69
|
-
|
|
70
|
-
```yaml
|
|
71
|
-
# .patina.yaml (project root)
|
|
72
|
-
max-models: [claude, gemini]
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
# Skill flavor (Claude Code / Codex CLI / Cursor / OpenCode):
|
|
77
|
-
/patina-max
|
|
78
|
-
|
|
79
|
-
[paste your text here]
|
|
80
|
-
```
|
|
68
|
+
When you want to compare how two backends rewrite the same paragraph, run them side by side and diff the outputs directly:
|
|
81
69
|
|
|
82
70
|
```bash
|
|
83
|
-
# Standalone CLI flavor — same idea, MAX mode runs each backend independently
|
|
84
71
|
patina --lang en --backend claude-cli draft.md > /tmp/claude.txt
|
|
85
72
|
patina --lang en --backend gemini-cli draft.md > /tmp/gemini.txt
|
|
86
73
|
diff /tmp/claude.txt /tmp/gemini.txt
|
|
87
74
|
```
|
|
88
75
|
|
|
89
|
-
|
|
76
|
+
This keeps the comparison explicit: you can read both rewrites, inspect which one preserves your meaning better, and keep whichever voice you prefer.
|
|
90
77
|
|
|
91
78
|
---
|
|
92
79
|
|
|
@@ -158,10 +145,10 @@ Block commits that introduce too-AI-sounding markdown. Drop this into `.git/hook
|
|
|
158
145
|
set -euo pipefail
|
|
159
146
|
changed=$(git diff --cached --name-only --diff-filter=ACM -- '*.md')
|
|
160
147
|
[ -z "$changed" ] && exit 0
|
|
161
|
-
patina --lang en --score --
|
|
148
|
+
patina --lang en --score --exit-on 30 --batch $changed
|
|
162
149
|
```
|
|
163
150
|
|
|
164
|
-
`--
|
|
151
|
+
`--exit-on` returns exit code `3` when any file's `overall` exceeds the threshold, which the shell treats as failure and aborts the commit. To bypass once (e.g. you intentionally want hype copy), commit with `--no-verify`.
|
|
165
152
|
|
|
166
153
|
---
|
|
167
154
|
|
package/docs/DEMO.md
CHANGED
|
@@ -2,18 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
A copy/paste demo for showing what patina does: remove AI packaging while keeping the claims intact.
|
|
4
4
|
|
|
5
|
+
The animated README heroes are language-suffixed:
|
|
6
|
+
|
|
7
|
+
- English README: [`assets/demo/patina-demo-en.gif`](../assets/demo/patina-demo-en.gif), using
|
|
8
|
+
[`examples/short/marketing-launch-en.md`](../examples/short/marketing-launch-en.md) →
|
|
9
|
+
[`examples/short/marketing-launch-en-rewritten.md`](../examples/short/marketing-launch-en-rewritten.md)
|
|
10
|
+
- Korean README: [`assets/demo/patina-demo-ko.gif`](../assets/demo/patina-demo-ko.gif), using
|
|
11
|
+
[`examples/short/marketing-launch.md`](../examples/short/marketing-launch.md) →
|
|
12
|
+
[`examples/short/marketing-launch-rewritten.md`](../examples/short/marketing-launch-rewritten.md)
|
|
13
|
+
- Chinese and Japanese READMEs currently fall back to the English GIF until
|
|
14
|
+
localized recordings are useful enough to maintain.
|
|
15
|
+
|
|
16
|
+
Re-recording notes live in [`assets/demo/README.md`](../assets/demo/README.md).
|
|
17
|
+
|
|
5
18
|
## 30-second terminal transcript
|
|
6
19
|
|
|
7
|
-
This transcript uses the checked-in
|
|
20
|
+
This transcript uses the checked-in English marketing fixture so the example is reviewable without screenshots or a live model run.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
$ cat examples/short/marketing-launch-en.md
|
|
24
|
+
The newly released Notion template pack is an innovative solution designed to transform productivity for modern teams. It offers 30 templates optimized for diverse workflows, with a user-friendly design that enables anyone to leverage them effortlessly. This product introduces a new paradigm for maximizing work efficiency.
|
|
25
|
+
|
|
26
|
+
$ patina --lang en --tone marketing examples/short/marketing-launch-en.md
|
|
27
|
+
If Notion still starts as a blank page for your team, open this pack first. It includes 30 templates for common workflows. Duplicate one, adjust the fields you need, and use it for a team project or your own planning without starting from scratch.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Full source/expected pair:
|
|
31
|
+
[`examples/short/marketing-launch-en.md`](../examples/short/marketing-launch-en.md) →
|
|
32
|
+
[`examples/short/marketing-launch-en-rewritten.md`](../examples/short/marketing-launch-en-rewritten.md).
|
|
33
|
+
|
|
34
|
+
## Korean terminal transcript
|
|
35
|
+
|
|
36
|
+
This is the Korean fixture used by `README_KR.md`.
|
|
8
37
|
|
|
9
38
|
```bash
|
|
10
39
|
$ cat examples/short/marketing-launch.md
|
|
11
40
|
새롭게 출시된 노션 템플릿 팩은 생산성 향상을 위한 혁신적인 솔루션입니다. 다양한 워크플로우에 최적화된 30개의 템플릿을 제공하며, 사용자 친화적인 디자인으로 누구나 손쉽게 활용 가능합니다. 본 제품은 업무 효율성을 극대화하는 새로운 패러다임을 제시합니다.
|
|
12
41
|
|
|
13
42
|
$ patina --lang ko --tone marketing examples/short/marketing-launch.md
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
노션을 매번 빈 페이지에서 시작했다면, 이제 그 시간부터 줄이세요.
|
|
43
|
+
노션을 자주 쓰지만 매번 빈 페이지에서 막힌다면 이 팩부터 열어 보세요. 업무별 템플릿 30개를 담았습니다. 복잡한 설정 없이 복제해서 바로 고치고, 팀 프로젝트든 개인 정리든 필요한 형태로 손보면 됩니다.
|
|
17
44
|
```
|
|
18
45
|
|
|
19
46
|
Full source/expected pair:
|
|
@@ -24,7 +51,7 @@ Full source/expected pair:
|
|
|
24
51
|
|
|
25
52
|
| Genre | Before | After |
|
|
26
53
|
|---|---|---|
|
|
27
|
-
| Korean marketing | “생산성 향상을 위한 혁신적인 솔루션… 업무 효율성을 극대화하는 새로운 패러다임” |
|
|
54
|
+
| Korean marketing | “생산성 향상을 위한 혁신적인 솔루션… 업무 효율성을 극대화하는 새로운 패러다임” | “업무별 템플릿 30개… 팀 프로젝트든 개인 정리든 필요한 형태로 손보면 됩니다.” |
|
|
28
55
|
| Academic | “획기적인 성과가 관찰되었으며… 중요한 역할을 수행할 수 있음을 시사한다” | “평균 구축 시간은 72시간에서 10분 이내로 줄었다… 일반화하기에는 주의가 필요하다.” |
|
|
29
56
|
| Technical | “핵심적인 역할을 수행… 차세대 AI 인프라 환경의 표준” | “GPU 자원 관리는 배포 속도와 운영 비용에 직접 영향을 준다… 검토할 만한 선택지다.” |
|
|
30
57
|
|
package/docs/EXIT-CODES.md
CHANGED
|
@@ -7,8 +7,7 @@ patina uses stable exit codes so CI and editor integrations can distinguish cont
|
|
|
7
7
|
| `0` | Success. For `--score --exit-on <n>`, the parsed `overall` score was at or below the threshold. |
|
|
8
8
|
| `1` | Runtime/backend failure: API/auth/backend errors, failed doctor blockers, invalid runtime setup, or unexpected exceptions. |
|
|
9
9
|
| `2` | Input/usage failure: unknown flags, missing required option values, empty stdin, or `--no-interactive` with no input. |
|
|
10
|
-
| `3` | Score gate exceeded. `--score --exit-on <n>`
|
|
11
|
-
| `4` | MAX mode could not produce a fully acceptable candidate: all candidates failed, or no candidate reached the MPS floor and patina selected the highest-MPS fallback. |
|
|
10
|
+
| `3` | Score gate exceeded. `--score --exit-on <n>` completed, but `overall > n`. |
|
|
12
11
|
|
|
13
12
|
## Score gates
|
|
14
13
|
|
|
@@ -16,7 +15,7 @@ patina uses stable exit codes so CI and editor integrations can distinguish cont
|
|
|
16
15
|
patina --lang en --score --exit-on 30 draft.md
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
`--
|
|
18
|
+
`--exit-on <n>` prints the score output as usual; only the process exit code changes to `3` when the threshold fails.
|
|
20
19
|
|
|
21
20
|
## Empty input
|
|
22
21
|
|