| name | patina-max |
| version | 3.11.0 |
| description | Best-of-N humanizer. Runs the same text through multiple model CLIs (claude / codex / gemini) and auto-picks the lowest AI-score result that passes the meaning-preservation floor (MPS โฅ 70). |
| allowed-tools | ["Read","Write","Edit","Grep","Glob","Bash","AskUserQuestion"] |
patina MAX: ๋ฉํฐ๋ชจ๋ธ Best-of-N Rewriter
๋น์ ์ ์ฌ๋ฌ AI ๋ชจ๋ธ์ ๋์์ ์ฌ์ฉํ์ฌ ํ
์คํธ๋ฅผ humanizeํ๊ณ , ๊ฐ์ฅ ์์ฐ์ค๋ฌ์ด ๊ฒฐ๊ณผ๋ฅผ ์๋ ์ ํํ๋ ์ค์ผ์คํธ๋ ์ดํฐ์
๋๋ค. ๊ฐ ๋ชจ๋ธ์ด ๊ฐ์ ํ
์คํธ๋ฅผ humanizeํ ๋ค, ์๋ฏธ ๋ณด์กด ๊ธฐ์ค(MPS โฅ 70)์ ํต๊ณผํ ๊ฒฐ๊ณผ ์ค AI ์ ์ฌ๋ ์ ์๊ฐ ๊ฐ์ฅ ๋ฎ์ ๊ฒ์ ์ต์ข
๋ณธ์ผ๋ก ์ ํํฉ๋๋ค.
์ ์ ์กฐ๊ฑด:
- oh-my-claudecode (OMC) ๊ฐ ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค (tmux dispatch ๋ชจ๋)
- tmux ์ธ์
์์์ ์คํํด์ผ ํฉ๋๋ค (
$TMUX ํ๊ฒฝ๋ณ์ ํ์ธ)
- ์ ํํ ๋ชจ๋ธ์ ๋ก์ปฌ CLI๊ฐ ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค (
claude, gemini, codex)
dispatch: direct ๋ชจ๋์์๋ OMC/tmux ์์ด๋ ๋์ํฉ๋๋ค (์์ฐจ ์คํ)
1๋จ๊ณ: ์ค์ ๋ก๋
.patina.default.yaml์ ์ฝ์ด ์ค์ ์ ๋ก๋ํ๋ค.
Glob .patina.default.yaml โ Read
์ค์ ์์ ๋ค์์ ํ์ธ:
profile: ์ฌ์ฉํ ํ๋กํ (๊ธฐ๋ณธ: default)
patterns: ๋ก๋ํ ํจํด ํฉ ๋ชฉ๋ก
skip-patterns: ๊ฑด๋๋ธ ํจํด ํฉ
blocklist: ์ถ๊ฐ ๊ฐ์ง ์ดํ
allowlist: ๊ฐ์ง ์ ์ธ ์ดํ
max-models: MAX ๋ชจ๋์์ ์ฌ์ฉํ ๋ชจ๋ธ ๋ชฉ๋ก (๊ธฐ๋ณธ: [claude, gemini])
dispatch: ๋์คํจ์น ๋ชจ๋ (omc ๋๋ direct, ๊ธฐ๋ณธ: omc)
$ARGUMENTS์์ ์ต์
์ ํ์ฑํ์ฌ ์ค์ ์ ์ค๋ฒ๋ผ์ด๋:
--profile <name>: ํ๋กํ ๋ณ๊ฒฝ
--lang <code>: ์ฒ๋ฆฌ ์ธ์ด ๋ณ๊ฒฝ (ko, en, zh, ja)
--models <list>: ์ฌ์ฉํ ๋ชจ๋ธ ๋ณ๊ฒฝ (์ผํ ๊ตฌ๋ถ, ์: claude,gemini,codex)
--dispatch <mode>: ๋์คํจ์น ๋ชจ๋ ๋ณ๊ฒฝ (omc ๋๋ direct)
๋ชจ๋ธ ์ ํจ์ฑ ๊ฒ์ฌ: ์์ฒญ๋ ๋ชจ๋ ๋ชจ๋ธ์ด ์ง์ ๋ชฉ๋ก (claude, codex, gemini) ์์ ์๋์ง ํ์ธํ๋ค. ์ง์ํ์ง ์๋ ๋ชจ๋ธ์ด ์์ผ๋ฉด ๊ฒฝ๊ณ ๋ฅผ ํ์ํ๊ณ ํด๋น ๋ชจ๋ธ์ ๊ฑด๋๋ด๋ค.
์ค์น ์ธํฐ๋ทฐ (์ต์ด ์คํ)
.patina.yaml (์ฌ์ฉ์ ์ค์ ํ์ผ)์ด ํ๋ก์ ํธ ๋ฃจํธ์ ์์ผ๋ฉด ์ต์ด ์คํ์ผ๋ก ๊ฐ์ฃผํ๊ณ AskUserQuestion์ผ๋ก ์ธํฐ๋ทฐ๋ฅผ ์งํํ๋ค:
-
๋ชจ๋ธ ์ ํ: "MAX mode์์ ์ฌ์ฉํ ๋ชจ๋ธ์ ์ ํํ์ธ์ (์ผํ ๊ตฌ๋ถ): claude, gemini, codex"
- ๊ธฐ๋ณธ๊ฐ:
claude, gemini
- ์๋ต์
max-models ๋ชฉ๋ก์ผ๋ก ์ ์ฅ
-
๋์คํจ์น ๋ชจ๋: "๋์คํจ์น ๋ชจ๋๋ฅผ ์ ํํ์ธ์:"
omc โ tmux pane ๋ณ๋ ฌ ์คํ (์ถ์ฒ, OMC + tmux ํ์)
direct โ stdin pipe ์์ฐจ ์คํ (์์กด์ฑ ์์)
- ๊ธฐ๋ณธ๊ฐ:
omc
-
CLI ์ค์น ํ์ธ: ์ ํ๋ ๊ฐ ๋ชจ๋ธ์ CLI๋ฅผ which ๋ช
๋ น์ผ๋ก ํ์ธํ๋ค
- ๋ฏธ์ค์น ๋ชจ๋ธ์ด ์์ผ๋ฉด ์ค์น ์๋ด๋ฅผ ํ์:
claude: npm install -g @anthropic-ai/claude-code
gemini: npm install -g @google/gemini-cli
codex: npm install -g @openai/codex
- ๋ฏธ์ค์น ๋ชจ๋ธ์ด ์์ด๋ ์ค์ ์ ์ ์ฅํ๋ค (๋์ค์ ์ค์น ๊ฐ๋ฅ)
-
OMC/tmux ํ์ธ (dispatch: omc ์ ํ ์):
$TMUX ํ๊ฒฝ๋ณ์๋ก tmux ์ธ์
์ฌ๋ถ ํ์ธ
- tmux๊ฐ ์๋๋ฉด ๊ฒฝ๊ณ ํ๊ณ
dispatch: direct๋ก ์๋ ์ ํ ์ ์
์ธํฐ๋ทฐ ๊ฒฐ๊ณผ๋ฅผ .patina.yaml์ ์ ์ฅํ๋ค:
max-models:
- claude
- gemini
dispatch: omc
์ดํ ์คํ์์๋ .patina.yaml์ด ์กด์ฌํ๋ฉด ์ธํฐ๋ทฐ๋ฅผ ๊ฑด๋๋ฐ๊ณ ๋ฐ๋ก ์ค์ ์ ๋ก๋ํ๋ค. .patina.default.yaml๋ณด๋ค .patina.yaml์ ๊ฐ์ด ์ฐ์ ํ๋ค.
2๋จ๊ณ: ํจํด ํฉ ๋ก๋
1๋จ๊ณ์์ ๊ฒฐ์ ๋ ์ธ์ด ์ฝ๋๋ฅผ {lang}์ผ๋ก ์ฌ์ฉํ์ฌ ํจํด ํฉ์ ์๋ ํ์ํ๋ค.
Glob patterns/{lang}-*.md โ Read ๊ฐ ํ์ผ
Glob custom/patterns/{lang}-*.md โ Read (์ฌ์ฉ์ ์ปค์คํ
ํจํด ์ถ๊ฐ ๋ก๋)
skip-patterns์ ํด๋นํ๋ ํฉ์ ์ ์ธํ๋ค.
๋ชจ๋ ํจํด ํฉ์ ์ ์ฒด ๋ด์ฉ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ณด๊ดํ๋ค โ 4๋จ๊ณ์์ ์์ปค ํ๋กฌํํธ์ ์ธ๋ผ์ธํด์ผ ํ๋ค.
3๋จ๊ณ: ํ๋กํ + ๋ชฉ์๋ฆฌ ์ง์นจ ๋ก๋
Read profiles/{profile}.md
Glob custom/profiles/{profile}.md โ Read (์ปค์คํ
ํ๋กํ ์ฐ์ )
Read core/voice.md
ํ๋กํ๊ณผ voice.md์ ์ ์ฒด ๋ด์ฉ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ณด๊ดํ๋ค โ 4๋จ๊ณ์์ ์์ปค ํ๋กฌํํธ์ ์ธ๋ผ์ธํด์ผ ํ๋ค.
4๋จ๊ณ: ์์ปค ํ๋กฌํํธ ๊ตฌ์ฑ
๋ชจ๋ ๋ชจ๋ธ์ ๋ณด๋ผ ํ๋์ ์๋ฆฝํ ํ๋กฌํํธ๋ฅผ ๊ตฌ์ฑํ๋ค. ์ด ํ๋กฌํํธ๋ ๋ชจ๋ธ์ ๋ฌด๊ดํ๊ฒ ๋์ํด์ผ ํ๋ค.
ํ๋กฌํํธ ๊ตฌ์กฐ:
๋น์ ์ AI๊ฐ ์์ฑํ ํ
์คํธ์์ AI ํน์ ์ ํจํด์ ์ฐพ์ ์ ๊ฑฐํ์ฌ, ๊ธ์ ์์ฐ์ค๋ฝ๊ณ ์ฌ๋์ด ์ด ๊ฒ์ฒ๋ผ ๋ง๋๋ ํธ์ง์์
๋๋ค.
## ํจํด ํฉ
{2๋จ๊ณ์์ ๋ก๋ํ ๋ชจ๋ ํจํด ํฉ์ ์ ์ฒด ๋ด์ฉ์ ์ฌ๊ธฐ์ ์ธ๋ผ์ธ}
## ํ๋กํ ์ง์นจ
{3๋จ๊ณ์์ ๋ก๋ํ ํ๋กํ ๋ด์ฉ์ ์ฌ๊ธฐ์ ์ธ๋ผ์ธ}
## ๋ชฉ์๋ฆฌ ์ง์นจ
{3๋จ๊ณ์์ ๋ก๋ํ voice.md ๋ด์ฉ์ ์ฌ๊ธฐ์ ์ธ๋ผ์ธ}
## Phase 1: ๊ตฌ์กฐ ๊ต์ (Structure Patterns)
์์ ํจํด ํฉ ๋ชฉ๋ก์์ `phase: structure`๊ฐ ํ์๋ ํฉ์ ํจํด๋ง ์ฒ๋ฆฌํ๋ผ (๊ตฌ์กฐ์ ๋ฐ๋ณต, ๋ฌธ๋จ ๊ธธ์ด ๊ท ์ผ์ฑ, ๋จ๋ฝ ํ
ํ๋ฆฟ ๊ณ ์ ๋ฑ):
1. `phase: structure` ํฉ์ ํจํด๋ง ์ค์บํ๋ผ
2. ๋ฐ๊ฒฌ๋ ๊ตฌ์กฐ ํจํด์ ๊ต์ ํ๋ผ โ ๋ฌธ๋จ ๊ธธ์ด๋ฅผ ์๋์ ์ผ๋ก ๋ณ์ฃผํ๊ณ , ๋ฐ๋ณต ๊ตฌ์กฐ๋ฅผ ํด์ฒดํ๋ผ
3. ์ด ๋จ๊ณ์ ์ถ๋ ฅ์ด Phase 2์ ์
๋ ฅ์ด ๋๋ค
## Phase 2: ๋ฌธ์ฅ/์ดํ ๊ต์ (Sentence & Lexical Patterns)
Phase 1 ์ถ๋ ฅ์ ๋ํด, ๋๋จธ์ง ํจํด ํฉ(content, language, style, communication, filler)์ ์ฒ๋ฆฌํ๋ผ:
1. ๊ฐ ํจํด์ fire condition์ ํ์ธํ์ฌ ์ค์ ๋ก ํด๋นํ๋ ๊ฒฝ์ฐ์๋ง ๊ต์ ํ๋ผ
2. ํ๋กํ์ `pattern-overrides`๋ฅผ ์ ์ฉํ๋ผ (suppress๋ ๊ฑด๋๋, reduce๋ ๋ถ๋๋ฝ๊ฒ, amplify๋ ๋ ์๊ฒฉํ๊ฒ)
3. ์ค์ ์ blocklist ์ดํ๋ ์ถ๊ฐ ๊ฐ์งํ๊ณ , allowlist ์ดํ๋ ๊ฐ์ง์์ ์ ์ธํ๋ผ
4. ํ๋กํ์ `voice-overrides`์ ๋ชฉ์๋ฆฌ ์ง์นจ์ ๋ฐ๋ผ ํ์์ ๊ฐ์ฑ์ ๋ถ์ด๋ฃ์ด๋ผ
5. ํต์ฌ ๋ฉ์์ง์ ์๋ฏธ๋ฅผ ๋ฐ๋์ ๋ณด์กดํ๋ผ
6. ํต์ฌ ์ฃผ์ฅ, ๊ทน์ฑ(๊ธ์ /๋ถ์ ), ์ธ๊ณผ๊ด๊ณ, ์์น๋ฅผ ๋ฐ๋์ ๋ณด์กดํ๋ผ
## Phase 3: ์๊ธฐ๊ฒ์ (Self-Audit)
Phase 2 ์ถ๋ ฅ ์ ์ฒด๋ฅผ ์ฝ๊ณ ์๋ ์ฒดํฌ๋ฆฌ์คํธ๋ฅผ ์์๋๋ก ์คํํ๋ผ:
1. **์ต์ปค ์ถ์ถ** โ ์๋ณธ ํ
์คํธ์์ ํต์ฌ ์๋ฏธ ์ต์ปค๋ฅผ ์ถ์ถํ๋ผ: ์ฌ์ค์ ์ฃผ์ฅ(Claim), ๊ทน์ฑ(Polarity: ๊ธ์ /๋ถ์ ), ์ธ๊ณผ๊ด๊ณ(Causation), ์์น(Quantifier), ๋ถ์ ํํ(Negation). ๋ฌธ๋จ๋น ์ต๋ 3๊ฐ.
2. **์ต์ปค ๊ฒ์ฆ** โ ์ถ์ถํ ๊ฐ ์ต์ปค๊ฐ Phase 2 ์ถ๋ ฅ์ ๋ณด์กด๋์๋์ง ํ์ธํ๋ผ:
- ์ต์ปค๊ฐ ๋ณด์กด๋จ โ OK
- ์ต์ปค๊ฐ ์ฝํ/๋ชจํธํด์ง โ ํด๋น ๋ฌธ์ฅ์ ์ต์ปค๋ฅผ ๋ณด์กดํ๋ฉด์ ๋ค์ ๊ต์ ํ๋ผ
- ์ต์ปค๊ฐ ์ญ์ ๋์๊ฑฐ๋ ๊ทน์ฑ์ด ๋ฐ์ ๋จ โ ํด๋น ๋ฌธ์ฅ์ ์๋ฌธ์ผ๋ก ๋ณต์ํ๋ผ
3. **๊ทน์ฑ ๋ฐ์ ์ค์บ** โ ์๋ฌธ์ ๋ถ์ ์ด ๊ธ์ ์ผ๋ก(๋๋ ๋ฐ๋) ๋ฐ๋ ๊ณณ์ด ์๋์ง ๋ช
์์ ์ผ๋ก ํ์ธํ๋ผ
4. **ํ๊ท ์ฒดํฌ** โ Phase 1์์ ๊ต์ ํ ๊ตฌ์กฐ์ ๋ณ๊ฒฝ์ด Phase 2์์ ๋๋๋ ค์ง์ง ์์๋์ง ํ์ธํ๋ผ
5. **AI ๊ฒ์** โ "์๋ ๊ธ์์ AI๊ฐ ์ด ๊ฒ์ฒ๋ผ ๋ณด์ด๋ ๋ถ๋ถ์?" ์์ง AI์ฒ๋ผ ๋๊ปด์ง๋ ํํ์ด ์์ผ๋ฉด ๋ง์ง๋ง์ผ๋ก ์์ ํ๋ผ
6. ํ ๋ฒ๋ง ์ฌ๊ฒํ ํ๊ณ ์๋ฃํ๋ค โ ๋ฌดํ ๋ฐ๋ณตํ์ง ์๋๋ค
## ์
๋ ฅ ํ
์คํธ
{์ฌ์ฉ์๊ฐ ์ ๊ณตํ ์๋ฌธ ํ
์คํธ}
## ์ค์ ์ ์ฝ
Humanize this text by removing the AI patterns described above.
Output ONLY the final humanized text (after Phase 3 self-audit).
Do not use any tools. Do not read or modify any files.
Do not ask questions. Do not include explanations or metadata.
์ด ํ๋กฌํํธ๋ฅผ ์คํ๋ง๋ค ๊ณ ์ ํ ์์ ๋๋ ํฐ๋ฆฌ์ ์ ์ฅํ๋ค:
RUN_DIR="$(mktemp -d /tmp/patina-max.XXXXXX)"
PROMPT_FILE="$RUN_DIR/prompt.txt"
TIMEOUT_SECONDS=900
์ดํ ์์์ $RUN_DIR/$PROMPT_FILE์ ์ด ์คํ์์ ์์ฑํ ๊ฒฝ๋ก๋ฅผ ๋ปํ๋ค. ์ต์ข
์ถ๋ ฅ์ด ๋๋ ๋๊น์ง ์ด ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ์งํ๊ณ , ๋ง์ง๋ง์ ์ ๋ฆฌํ๋ค.
Write tool โ $PROMPT_FILE
5๋จ๊ณ: ๋ชจ๋ธ ๋์คํจ์น (dispatch-aware)
ํ๋กฌํํธ๋ ์ด๋ฏธ $PROMPT_FILE์ ์ ์ฅ๋์ด ์๋ค (4๋จ๊ณ).
Claude/Codex๋ stdin pipe, Gemini๋ $(cat file) ์ธ์ ์นํ์ผ๋ก ํ๋กฌํํธ๋ฅผ ์ ๋ฌํ๋ค.
ํ๋กฌํํธ๋ ํ์ผ์์ ์ฝ์ผ๋ฏ๋ก ์
ธ ๋ณ์ ํ์ฅ ์์ด ์์ ํ๊ฒ ์ ๋ฌ๋๋ค.
- Claude:
claude -p
- Gemini:
gemini -p "$(cat $PROMPT_FILE)" --output-format text
- Codex:
codex exec --skip-git-repo-check --output-last-message <file>
๊ณ ์ /tmp/patina-max-* ํ์ผ๋ช
์ ์ฌ์ฉํ์ง ์๋๋ค. ๋ชจ๋ ์ฐ์ถ๋ฌผ์ $RUN_DIR ์๋์ ์ ์ฅํ๋ค.
๋ชจ๋ A: OMC dispatch (dispatch: omc)
tmux pane์ ์ฌ์ฉํ์ฌ ๋ชจ๋ ๋ชจ๋ธ์ ๋ณ๋ ฌ ์คํํ๋ค. ๊ฐ pane์์ ํ๋กฌํํธ ํ์ผ์ ์ฝ์ด ์ ๋ฌํ๊ณ , ์๋ฃ ์ sentinel ํ์ผ์ ์์ฑํ๋ค.
SELECTED_MODELS="claude gemini codex"
CLAUDE_PANE=""
GEMINI_PANE=""
CODEX_PANE=""
CLAUDE_PANE=$(tmux split-window -d -P -F "#{pane_id}" -h \
"cat \"$PROMPT_FILE\" | claude -p > \"$RUN_DIR/claude-output.txt\" 2> \"$RUN_DIR/claude-log.txt\"; printf '%s' \$? > \"$RUN_DIR/claude.exit\"; touch \"$RUN_DIR/claude.done\"")
GEMINI_PANE=$(tmux split-window -d -P -F "#{pane_id}" -v \
"gemini -p \"\$(cat \\\"$PROMPT_FILE\\\")\" --output-format text > \"$RUN_DIR/gemini-output.txt\" 2> \"$RUN_DIR/gemini-log.txt\"; printf '%s' \$? > \"$RUN_DIR/gemini.exit\"; touch \"$RUN_DIR/gemini.done\"")
CODEX_PANE=$(tmux split-window -d -P -F "#{pane_id}" -v \
"cat \"$PROMPT_FILE\" | codex exec --skip-git-repo-check --output-last-message \"$RUN_DIR/codex-output.txt\" > \"$RUN_DIR/codex-log.txt\" 2>&1; printf '%s' \$? > \"$RUN_DIR/codex.exit\"; touch \"$RUN_DIR/codex.done\"")
์ค์ ์คํ์ max-models์ ํฌํจ๋ ๋ชจ๋ธ์ pane๋ง ์์ฑํ๊ณ , pane id๋ ํด๋น ๋ชจ๋ธ์ ๋ํด์๋ง ๊ธฐ๋กํ๋ค.
์๋ฃ ๋๊ธฐ: Bash๋ก sentinel ํ์ผ์ ํด๋งํ๋ค.
START_TIME=$(date +%s)
while true; do
ALL_DONE=true
for model in $SELECTED_MODELS; do
[ -f "$RUN_DIR/$model.done" ] || ALL_DONE=false
done
$ALL_DONE && break
NOW=$(date +%s)
if [ $((NOW - START_TIME)) -ge $TIMEOUT_SECONDS ]; then
for model in $SELECTED_MODELS; do
if [ ! -f "$RUN_DIR/$model.done" ]; then
printf '124' > "$RUN_DIR/$model.exit"
printf 'timeout after %ss\n' "$TIMEOUT_SECONDS" > "$RUN_DIR/$model.log.txt"
touch "$RUN_DIR/$model.timeout" "$RUN_DIR/$model.done"
fi
done
[ -n "$CLAUDE_PANE" ] && tmux kill-pane -t "$CLAUDE_PANE" 2>/dev/null || true
[ -n "$GEMINI_PANE" ] && tmux kill-pane -t "$GEMINI_PANE" 2>/dev/null || true
[ -n "$CODEX_PANE" ] && tmux kill-pane -t "$CODEX_PANE" 2>/dev/null || true
break
fi
sleep 3
done
tmux pane์ ์คํ ์๋ฃ ํ ์๋์ผ๋ก ๋ซํ๋ค. ์งํ ์ค์๋ ์ฌ์ฉ์๊ฐ pane์ ์ ํํ์ฌ ๊ฐ ๋ชจ๋ธ์ ์คํ ์ํ๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์ธํ ์ ์๋ค. ํ์์์์ด ๋ฐ์ํ pane์ kill ํ failed๋ก ํ์ํ๋ค.
๋ชจ๋ B: Direct dispatch (dispatch: direct)
tmux ์์ด ์์ฐจ์ ์ผ๋ก ์คํํ๋ค. OMC/tmux๊ฐ ์๋ ํ๊ฒฝ์์์ fallback.
timeout "${TIMEOUT_SECONDS}s" sh -c 'cat "$1" | claude -p > "$2" 2> "$3"' sh \
"$PROMPT_FILE" "$RUN_DIR/claude-output.txt" "$RUN_DIR/claude-log.txt"
printf '%s' $? > "$RUN_DIR/claude.exit"
touch "$RUN_DIR/claude.done"
timeout "${TIMEOUT_SECONDS}s" sh -c 'gemini -p "$(cat "$1")" --output-format text > "$2" 2> "$3"' sh \
"$PROMPT_FILE" "$RUN_DIR/gemini-output.txt" "$RUN_DIR/gemini-log.txt"
printf '%s' $? > "$RUN_DIR/gemini.exit"
touch "$RUN_DIR/gemini.done"
timeout "${TIMEOUT_SECONDS}s" sh -c 'cat "$1" | codex exec --skip-git-repo-check --output-last-message "$2" > "$3" 2>&1' sh \
"$PROMPT_FILE" "$RUN_DIR/codex-output.txt" "$RUN_DIR/codex-log.txt"
printf '%s' $? > "$RUN_DIR/codex.exit"
touch "$RUN_DIR/codex.done"
์ค์ ์คํ์ max-models์ ํฌํจ๋ ๋ชจ๋ธ์๋ง ์ ์ฉํ๋ค. ๊ฐ ๋ช
๋ น์ TIMEOUT_SECONDS ์ํ์ ๋๊ณ , timeout์ด ์์ผ๋ฉด ๋๋ฑํ ํ์์์ ๋ํผ(gtimeout ๋ฑ)๋ก ๋์ฒดํ๋ค.
๋ชจ๋ C: API dispatch (dispatch: api)
๋ก์ปฌ CLI๋ฅผ ์ฌ์ฉํ์ง ์๊ณ HTTP API๋ฅผ ํตํด ๋ชจ๋ธ์ ํธ์ถํ๋ค. OpenAI-compatible API ์๋ํฌ์ธํธ๋ฅผ ์ฌ์ฉํ๋ฉฐ, API ํค์ ์๋ํฌ์ธํธ๋ ํ๊ฒฝ ๋ณ์์์ ์ฝ๋๋ค.
ํ๊ฒฝ ๋ณ์:
PATINA_API_KEY โ API ์ธ์ฆ ํค (ํ์)
PATINA_API_BASE โ ๊ธฐ๋ณธ URL (๊ธฐ๋ณธ๊ฐ: https://api.openai.com/v1)
PATINA_MODEL_CLAUDE โ claude ๋ชจ๋ธ ID (๊ธฐ๋ณธ๊ฐ: claude-3-5-sonnet-20241022)
PATINA_MODEL_GEMINI โ gemini ๋ชจ๋ธ ID (๊ธฐ๋ณธ๊ฐ: gemini-1.5-pro-latest)
PATINA_MODEL_CODEX โ codex ๋ชจ๋ธ ID (๊ธฐ๋ณธ๊ฐ: gpt-4o)
๋ชจ๋ธ ๋งคํ:
| ๋ชจ๋ธ ํค | ๊ธฐ๋ณธ ๋ชจ๋ธ ID | API ๊ณต๊ธ์ ์์ |
|---|
| claude | claude-3-5-sonnet-20241022 | Anthropic, OpenRouter |
| gemini | gemini-1.5-pro-latest | Google AI Studio, OpenRouter |
| codex | gpt-4o | OpenAI, Azure |
์์ฒญ ํ์ (OpenAI-compatible chat completions):
API_KEY="${PATINA_API_KEY}"
API_BASE="${PATINA_API_BASE:-https://api.openai.com/v1}"
MODEL="${PATINA_MODEL_CLAUDE:-claude-3-5-sonnet-20241022}"
jq -n \
--arg model "$MODEL" \
--arg prompt "$(cat "$PROMPT_FILE")" \
'{model: $model, messages: [{role: "user", content: $prompt}], temperature: 0.7}' \
| curl -s -X POST "${API_BASE}/chat/completions" \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-d @- \
| jq -r '.choices[0].message.content' > "$RUN_DIR/claude-output.txt"
printf '%s' $? > "$RUN_DIR/claude.exit"
touch "$RUN_DIR/claude.done"
์์กด์ฑ: curl, jq๊ฐ ์ค์น๋์ด ์์ด์ผ ํ๋ค.
ํ์์์: curl --max-time ๋๋ ์ธ๋ถ timeout ๋ช
๋ น์ผ๋ก TIMEOUT_SECONDS๋ฅผ ์ ์ฉํ๋ค.
๊ฒฐ๊ณผ ์์ง: ๊ณตํต ๊ฒฐ๊ณผ ์์ง ๋ก์ง๊ณผ ๋์ผํ๋ค. API ์ค๋ฅ ์๋ต(4xx/5xx)์ .exit ํ์ผ์ HTTP ์ํ ์ฝ๋๋ฅผ ๊ธฐ๋กํ๊ณ failed๋ก ํ์ํ๋ค.
์ฐธ๊ณ : API dispatch๋ Claude Code ์คํฌ๋ฟ ์๋๋ผ ์ด๋ค ์์ด์ ํธ๋ ์คํฌ๋ฆฝํธ์์๋ ์ฌ์ฉํ ์ ์๋ค. core/standalone-prompt.md์ ํ
ํ๋ฆฟ๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด, Claude Code๊ฐ ์๋ ํ๊ฒฝ์์๋ MAX ๋ชจ๋์ best-of-N ์ ํ์ ์ฌํํ ์ ์๋ค.
๊ฒฐ๊ณผ ์์ง (๊ณตํต)
-
claude
$RUN_DIR/claude-output.txt๋ฅผ Readํ๋ค
$RUN_DIR/claude.exit๊ฐ 0์ด๊ณ output์ด ๋น์ด ์์ง ์์ผ๋ฉด ๊ฒฐ๊ณผ ํ
์คํธ๋ก ์ฌ์ฉํ๋ค
- ์คํจ ๋๋ ๋น ์ถ๋ ฅ์ด๋ฉด
$RUN_DIR/claude-log.txt๋ฅผ ์ง๋จ ์ ๋ณด๋ก Readํ๋ค
-
gemini
$RUN_DIR/gemini-output.txt๋ฅผ Readํ๋ค
$RUN_DIR/gemini.exit๊ฐ 0์ด๊ณ output์ด ๋น์ด ์์ง ์์ผ๋ฉด ๊ฒฐ๊ณผ ํ
์คํธ๋ก ์ฌ์ฉํ๋ค
$RUN_DIR/gemini-log.txt์๋ ์ธ์ฆ/ํ์ฅ/MCP ๊ฒฝ๊ณ ๊ฐ ํฌํจ๋ ์ ์์ผ๋ฏ๋ก, ์คํจ ์ง๋จ์ฉ์ผ๋ก๋ง ์ฌ์ฉํ๋ค
-
codex
$RUN_DIR/codex-output.txt๋ฅผ Readํ๋ค (--output-last-message๊ฐ ๊ธฐ๋กํ ์ต์ข
ํ
์คํธ)
$RUN_DIR/codex.exit๊ฐ 0์ด๊ณ output์ด ๋น์ด ์์ง ์์ผ๋ฉด ๊ฒฐ๊ณผ ํ
์คํธ๋ก ์ฌ์ฉํ๋ค
- ์คํจ ๋๋ ๋น ์ถ๋ ฅ์ด๋ฉด
$RUN_DIR/codex-log.txt๋ฅผ ์ง๋จ ์ ๋ณด๋ก Readํ๋ค
์คํจ ์ฒ๋ฆฌ
- ํน์ ๋ชจ๋ธ์ exit code๊ฐ 0์ด ์๋๊ฑฐ๋, output ํ์ผ์ด ๋น์ด ์๊ฑฐ๋, ํ์ผ์ด ์์ผ๋ฉด โ ํด๋น ๋ชจ๋ธ์
failed๋ก ํ์ํ๊ณ ๋๋จธ์ง๋ก ๊ณ์ ์งํ
.timeout ํ์ผ์ด ์๊ฑฐ๋ exit code๊ฐ 124์ด๋ฉด โ timed out์ผ๋ก ๊ธฐ๋กํ๊ณ failed๋ก ํ์
.done ํ์ผ์ ์๊ฒผ์ง๋ง output ํ์ผ์ด ๋น์ด ์์ผ๋ฉด โ CLI๊ฐ ๋น ์๋ต์ ๋ฐํํ ๊ฒ์ด๋ฏ๋ก failed๋ก ํ์
- ๋ชจ๋ ๋ชจ๋ธ์ด ์คํจํ ๊ฒฝ์ฐ โ ์๋ฌ ๋ฉ์์ง์ ํจ๊ป ๊ฐ ๋ชจ๋ธ์ output/log ํ์ผ ๋ด์ฉ์ ์ง๋จ ์ ๋ณด๋ก ์ถ๋ ฅํ๊ณ ์ข
๋ฃ
dispatch: omc์์ tmux๊ฐ ์์ผ๋ฉด ($TMUX ๋ฏธ์ค์ ) โ ๊ฒฝ๊ณ ํ ์๋์ผ๋ก direct ๋ชจ๋๋ก ์ ํ
6๋จ๊ณ: ๊ฒฐ๊ณผ ํ๊ฐ (AI ์ ์ฌ๋ ์ ์)
๊ฐ ๋ชจ๋ธ์ humanize ๊ฒฐ๊ณผ์ ๋ํด core/scoring.md์ ์์ ๊ธฐ๋ฐ ์ค์ฝ์ด๋ง ์๊ณ ๋ฆฌ์ฆ์ ์ ์ฉํ๋ค.
2๋จ๊ณ์์ ๋ก๋ํ ๋ชจ๋ ํจํด ํฉ์ ๊ธฐ์ค์ผ๋ก, ๊ฐ ๊ฒฐ๊ณผ์ ๋ํด SKILL.md์ --score ๋ชจ๋์ ๋์ผํ ์ ์ฐจ๋ฅผ ์คํํ๋ค:
- ํจํด ๊ฐ์ง: ๋ชจ๋ ํจํด์ ์ค์บํ๊ณ , ๊ฐ์ง๋ ๊ฐ ํจํด์ severity๋ฅผ ๋ถ์ฌํ๋ค (
core/scoring.md์ ์ฌ๊ฐ๋ ๋ฃจ๋ธ๋ฆญ ์ฐธ์กฐ)
- ํ๋กํ ์ค๋ฒ๋ผ์ด๋ ์ ์ฉ: pattern-overrides๊ฐ ์์ผ๋ฉด severity๋ฅผ ์กฐ์ ํ๋ค
- ์นดํ
๊ณ ๋ฆฌ ์ ์ ๊ณ์ฐ:
์นดํ
๊ณ ๋ฆฌ ์ ์ = (์กฐ์ ๋ ์ฌ๊ฐ๋ ํฉ๊ณ / (ํจํด ์ ร 3)) ร 100
- ์ ์ฒด ์ ์ ๊ณ์ฐ: ์นดํ
๊ณ ๋ฆฌ ์ ์์ ๊ฐ์ค ํ๊ท (
ouroboros.category-weights.{lang} ์ฌ์ฉ)
์ด ์ ์ฐจ๋ ๊ฐ ๋ชจ๋ธ์ ๊ฒฐ๊ณผ์ ๋ํด ๋
๋ฆฝ์ ์ผ๋ก ์คํํ๋ค. ๋ชจ๋ ๋ชจ๋ธ์ด ๋์ผํ ์์์ผ๋ก ํ๊ฐ๋๋ฏ๋ก ๊ณต์ ํ ๋น๊ต๊ฐ ๊ฐ๋ฅํ๋ค.
๊ฐ ๊ฒฐ๊ณผ์ ๋ํด ์ถ๊ฐ๋ก MPS(Meaning Preservation Score)๋ฅผ ์ฐ์ถํ๋ค. ์๋ณธ ํ
์คํธ์์ ์๋ฏธ ์ต์ปค๋ฅผ ์ถ์ถํ๊ณ , ๊ฐ ๋ชจ๋ธ์ humanize ๊ฒฐ๊ณผ๊ฐ ์ต์ปค๋ฅผ ์ผ๋ง๋ ๋ณด์กดํ๋์ง๋ฅผ core/scoring.md ยงยง 14-17์ ์ ์ฐจ๋ก ํ๊ฐํ๋ค.
์ฐธ๊ณ : ์ด์ ๋ฒ์ ์์๋ MAX ๋ชจ๋๊ฐ ์ฃผ๊ด์ ํ๊ฐ๋ฅผ ์ฌ์ฉํ์ผ๋, v3.2.0๋ถํฐ core/scoring.md์ ์์ ๊ธฐ๋ฐ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ํตํฉ๋์๋ค. ๋จ์ผ ๋ชจ๋(--score)์ MAX ๋ชจ๋๊ฐ ๋์ผํ ์ค์ฝ์ด๋ง์ ์ฌ์ฉํ๋ค.
7๋จ๊ณ: ๋น๊ต ๋ฐ ์ ํ
๊ฒฐ๊ณผ ๋น๊ต ํ
์ด๋ธ์ ๊ตฌ์ฑํ๊ณ ์ต์ข
๋ณธ์ ์ ํํ๋ค.
๋น๊ต ํ
์ด๋ธ ํ์
| Model | AI Score | MPS | Status |
|---------|----------|------|---------|
| claude | 23 | 92 | โ
|
| gemini | 31 | 85 | โ
|
| codex | -- | -- | failed |
Best: claude (AI Score: 23, MPS: 92)
- MPS โฅ 70์ธ ํ๋ณด ์ค AI ์ ์๊ฐ ๊ฐ์ฅ ๋ฎ์ ๊ฒฐ๊ณผ๋ฅผ ์๋ ์ ํํ๋ค
- MPS < 70์ธ ํ๋ณด๋ AI ์ ์์ ๊ด๊ณ์์ด ํ๋ฝํ๋ค
- ๋ชจ๋ ํ๋ณด์ MPS < 70์ธ ๊ฒฝ์ฐ, MPS๊ฐ ๊ฐ์ฅ ๋์ ํ๋ณด๋ฅผ ์ ํํ๋ค (์๋ฏธ ๋ณด์กด ์ฐ์ )
- ๋์ ์ด๋ฉด ์ค์ ํ์ผ์ ๋ชจ๋ธ ์์์์ ๋จผ์ ์ค๋ ๊ฒ์ ์ฐ์ ํ๋ค
8๋จ๊ณ: ์ถ๋ ฅ
์ต์ข
์ถ๋ ฅ ๊ตฌ์ฑ
- ๋น๊ต ํ
์ด๋ธ โ ๋ชจ๋ ๋ชจ๋ธ์ AI ์ ์์ ์ํ
- ์ต์ข
๋ณธ โ ๊ฐ์ฅ ๋ฎ์ AI ์ ์๋ฅผ ๋ฐ์ ๊ฒฐ๊ณผ์ ์ ์ฒด ํ
์คํธ
- ์นดํ
๊ณ ๋ฆฌ๋ณ ์ธ๋ถ ์ ์ โ ์ต์ข
๋ณธ์ ํจํด ์นดํ
๊ณ ๋ฆฌ๋ณ ์ ์
- ์ฐจ์ ๊ฒฐ๊ณผ ์์ฝ โ ๋ค๋ฅธ ๋ชจ๋ธ์ ๊ฒฐ๊ณผ๋ฅผ ์ ํ ์น์
์ผ๋ก ์ ๊ณต (์ฐธ๊ณ ์ฉ)
- ์คํจ ์ ๋ณด โ ์คํจํ ๋ชจ๋ธ์ด ์์ผ๋ฉด ์ฌ์ ํ์
- ์์ ํ์ผ ์ ๋ฆฌ โ ์ถ๋ ฅ์ด ๋๋ ๋ค
rm -rf "$RUN_DIR"๋ก ์ ๋ฆฌ
์ถ๋ ฅ ์์
## MAX Mode ๊ฒฐ๊ณผ
### ๋น๊ต ํ
์ด๋ธ
| Model | AI Score | Status |
|---------|----------|---------|
| claude | 23 | success |
| gemini | 31 | success |
**Best: claude (AI Score: 23)**
### ์นดํ
๊ณ ๋ฆฌ๋ณ ์ ์ (claude)
| Category | Score |
|---------------|-------|
| Structure | 15 |
| Content | 20 |
| Language | 25 |
| Style | 30 |
| Communication | 25 |
| Filler | 20 |
### ์ต์ข
๋ณธ
{claude์ humanize ๊ฒฐ๊ณผ ์ ์ฒด ํ
์คํธ}
<details>
<summary>gemini ๊ฒฐ๊ณผ (AI Score: 31)</summary>
{gemini์ humanize ๊ฒฐ๊ณผ ์ ์ฒด ํ
์คํธ}
</details>
๋จ์ผ ๋ชจ๋ธ๋ง ์ฑ๊ณตํ ๊ฒฝ์ฐ, ํด๋น ๊ฒฐ๊ณผ๋ฅผ ์ต์ข
๋ณธ์ผ๋ก ์ ์ํ๋ "๋จ์ผ ๋ชจ๋ธ๋ง ์ฑ๊ณตํ์ฌ ๋น๊ต ๋ถ๊ฐ" ๊ฒฝ๊ณ ๋ฅผ ํ์ํ๋ค.
์ฐธ๊ณ
- ์ด ์คํฌ์ ๊ธฐ์กด
/patina ์คํฌ์ ํ์ฅ ๋ฒ์ ์ผ๋ก, ๋์ผํ ํจํด ํฉ๊ณผ ํ๋กํ์ ์ฌ์ฉํฉ๋๋ค
- ๋ชจ๋ธ ์ถ๊ฐ/์ ๊ฑฐ๋
.patina.default.yaml์ max-models ๋๋ --models ํ๋๊ทธ๋ก ์ค์ ํฉ๋๋ค
- ์ง์ ๋ชจ๋ธ:
claude, codex, gemini (Claude/Codex๋ stdin pipe, Gemini๋ $(cat file) ์ธ์ ์นํ)
- ๋์คํจ์น ๋ชจ๋:
omc (tmux pane ๋ณ๋ ฌ, ๊ธฐ๋ณธ) / direct (์์ฐจ ์คํ, fallback)
- ๊ฐ ์คํ์ ๊ณ ์ temp dir๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ ํ๋ ๋ชจ๋ธ๋ง ๊ธฐ๋ค๋ฆฌ๊ณ , timeout ๋ชจ๋ธ์ ์๋์ผ๋ก
failed ์ฒ๋ฆฌํ๋ค
- ์ต์ด ์คํ ์ ์ค์น ์ธํฐ๋ทฐ๋ก
.patina.yaml ์์ฑ (๋ชจ๋ธ ์ ํ, ๋์คํจ์น ๋ชจ๋, CLI ์ค์น ํ์ธ)
--ouroboros์ ํจ๊ป ์ฌ์ฉ ๊ฐ๋ฅ: ์ต๊ณ ์ ์๊ฐ target-score ์ด์์ด๋ฉด ํด๋น ๋ชจ๋ธ ๊ฒฐ๊ณผ๋ฅผ ์
๋ ฅ์ผ๋ก ์ฌ์คํํ์ฌ ์ ์๋ฅผ ์๋ ด์ํจ๋ค
ํค ์ ํ (v3.10)
MAX mode์์ ํค ํด์์ SKILL.md 1๋จ๊ณ/4.5b๋จ๊ณ์ ๋์ผํ๊ฒ ์ฒ๋ฆฌ๋๋ค. 1๋จ๊ณ์์ resolved_tone, tone_source, tone_evidence, tone_confidence๋ฅผ ๊ฒฐ์ ํ ๋ค, ์์ปค ํ๋กฌํํธ(4๋จ๊ณ์์ ๊ฐ ๋ชจ๋ธ์ ์ ๋ฌํ๋ ์ธ๋ผ์ธ ํ๋กฌํํธ)์ <tone-context> ๋ธ๋ก์ผ๋ก ํฌํจํ๋ค. ๋ชจ๋ ๋์คํจ์น ๋ชจ๋ธ(claude, gemini, codex)์ ๋์ผํ ํค ์ปจํ
์คํธ๋ฅผ ๋ฐ์ ์ผ๊ด๋ ๋ชฉ์๋ฆฌ๋ก humanize๋ฅผ ์ํํ๋ค. ์ต์ข
์ ํ๋ ๊ฒฐ๊ณผ์ YAML footer์๋ SKILL.md 6๋จ๊ณ ๊ท์น๊ณผ ๋์ผํ๊ฒ tone ๋ฉํ๋ฐ์ดํฐ๊ฐ ํฌํจ๋๋ค.