@kaydash9999/banker-plugins 0.26.0 → 0.27.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.
Files changed (32) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +30 -0
  4. package/README.md +10 -7
  5. package/bin/lib/codex-hooks.mjs +7 -1
  6. package/codex/command-skills/front-qa/SKILL.md +3 -1
  7. package/codex/hooks.json +15 -5
  8. package/codex/manifest.json +2 -1
  9. package/codex/skills/ralph/SKILL.md +272 -0
  10. package/codex/skills/ralph/scripts/gate-evidence.mjs +457 -0
  11. package/codex/skills/ralph/scripts/ralph-state.mjs +622 -0
  12. package/codex/skills/ralph/scripts/run-folder.mjs +299 -0
  13. package/codex/transform-matrix.md +6 -5
  14. package/commands/front-qa.md +3 -1
  15. package/hooks/ralph-continue-codex.mjs +59 -0
  16. package/package.json +1 -1
  17. package/skills/all-in-one/SKILL.md +22 -8
  18. package/skills/make-evidence/SKILL.md +207 -131
  19. package/skills/make-evidence/scripts/evidence.mjs +162 -0
  20. package/skills/make-evidence/scripts/me-check.mjs +125 -0
  21. package/skills/make-evidence/scripts/me-commit.mjs +48 -0
  22. package/skills/make-evidence/scripts/me-git.mjs +63 -0
  23. package/skills/make-evidence/scripts/me-oracle.mjs +244 -0
  24. package/skills/make-evidence/scripts/me-precheck.mjs +122 -0
  25. package/skills/make-evidence/scripts/me-run.mjs +214 -0
  26. package/skills/ralph-qa/references/gate-evidence.mjs +3 -3
  27. package/skills/ralph-qa/references/run-folder.mjs +3 -3
  28. package/skills/ultra-chain/SKILL.md +11 -4
  29. package/skills/ultra-init/SKILL.md +9 -7
  30. package/skills/ultraqa/references/gate-evidence.mjs +3 -3
  31. package/skills/ultraqa/references/run-folder.mjs +3 -3
  32. package/skills/visual-ralph/SKILL.md +9 -4
@@ -0,0 +1,214 @@
1
+ // make-evidence: runs a command into a log (secrets masked, exit code kept, time limit over the process tree),
2
+ // and starts or stops a server. Pure Node, no network beyond the ready check on the URL it is given.
3
+ import { spawn, spawnSync } from "node:child_process";
4
+ import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync, writeSync } from "node:fs";
5
+ import { dirname, resolve } from "node:path";
6
+ import { EXCLUDE, Usage, git, lines, runDir, stamp } from "./me-git.mjs";
7
+
8
+ // ---- secrets --------------------------------------------------------------------------------------------------
9
+
10
+ const KEYWORD = "(?:password|passwd|pwd|secret|token|api[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret|credential)";
11
+ const SECRETS = [
12
+ [/(authorization:\s*(?:bearer|basic|token)\s+)[^\s"']+/gi, "$1***"],
13
+ [new RegExp(`(\\b[A-Za-z0-9_]*${KEYWORD}[A-Za-z0-9_]*["']?\\s*[:=]\\s*["']?)[^\\s"'&,;]+`, "gi"), "$1***"],
14
+ [new RegExp(`(--?${KEYWORD}[A-Za-z0-9_-]*(?:=|\\s+))[^\\s"'-][^\\s"']*`, "gi"), "$1***"],
15
+ [/(\bmysql(?:dump)?\b[^\n]*?\s-p)[^\s"']+/gi, "$1***"],
16
+ [/(\b[a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)[^\s@/]+@/gi, "$1***@"],
17
+ [/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "***"],
18
+ [/\b(?:sk-[A-Za-z0-9_-]{16,}|sk_(?:live|test)_[A-Za-z0-9]{10,}|gh[pousr]_[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|xox[abpr]-[A-Za-z0-9-]{10,}|eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,})/g, "***"],
19
+ [/(\b(?:cookie|set-cookie):\s*)\S[^\r\n]*/gi, "$1***"],
20
+ ];
21
+
22
+ export function redact(text) {
23
+ let n = 0;
24
+ for (const [re, to] of SECRETS) {
25
+ for (const m of text.matchAll(re)) if (!m[0].endsWith("***") && !m[0].endsWith("***@")) n++;
26
+ text = text.replace(re, (...m) => (m[0].endsWith("***") || m[0].endsWith("***@") ? m[0] : m[0].replace(new RegExp(re.source, re.flags.replace("g", "")), to)));
27
+ }
28
+ return { text, n };
29
+ }
30
+
31
+ // Places in a text that still look like a secret (already masked ones do not count): line numbers only.
32
+ export function secretLines(text) {
33
+ const hits = new Set();
34
+ const all = text.split("\n");
35
+ all.forEach((line, i) => { if (redact(line).n) hits.add(i + 1); });
36
+ if (redact(text).n && !hits.size) hits.add(1); // a block over several lines
37
+ return [...hits];
38
+ }
39
+
40
+ // ---- logs -----------------------------------------------------------------------------------------------------
41
+
42
+ const quote = (a) => (/^[\w@%+=:,./-]+$/.test(a) ? a : `'${a.replace(/'/g, "'\\''")}'`);
43
+
44
+ // The log file to write: {ts} (or @TS@, which PowerShell leaves alone unquoted) filled in, the folder made, an
45
+ // existing file refused.
46
+ export function claimLog(name) {
47
+ const file = resolve(name.replace(/\{ts\}|@TS@/g, stamp()));
48
+ mkdirSync(dirname(file), { recursive: true });
49
+ if (existsSync(file)) throw new Error(`로그가 이미 있음(덮어쓰지 않음): ${file}`);
50
+ return file;
51
+ }
52
+
53
+ function headInfo(cwd) {
54
+ const r = git(cwd, ["rev-parse", "HEAD"]);
55
+ if (r.status !== 0) return { sha: "none", dirty: "?" };
56
+ const s = git(cwd, ["--no-optional-locks", "status", "--porcelain", "--", ".", ...EXCLUDE]);
57
+ return { sha: r.stdout.trim(), dirty: s.status === 0 ? lines(s.stdout).length : "?" };
58
+ }
59
+
60
+ export function header(argv, shell, cwd) {
61
+ const shown = redact(shell ? argv.join(" ") : argv.map(quote).join(" ")).text;
62
+ const h = headInfo(cwd);
63
+ return `$ ${shown}\n# head=${h.sha} dirty=${h.dirty} at=${new Date().toISOString()} node=${process.version} os=${process.platform} cwd=${cwd}\n`;
64
+ }
65
+
66
+ function spawnArgs(argv, shell) {
67
+ if (!shell) return [argv[0], argv.slice(1)];
68
+ const line = argv.join(" ");
69
+ return process.platform === "win32" ? ["powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", line]] : ["/bin/sh", ["-c", line]];
70
+ }
71
+
72
+ export function killTree(pid) {
73
+ if (!pid) return;
74
+ if (process.platform === "win32") {
75
+ spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], { cwd: runDir(), stdio: "ignore", windowsHide: true });
76
+ return;
77
+ }
78
+ try { process.kill(-pid, "SIGKILL"); } catch { try { process.kill(pid, "SIGKILL"); } catch { /* already gone */ } }
79
+ }
80
+
81
+ // Writes whole lines, masked, in the order they arrive; a partial line waits for its end.
82
+ function lineSink(fd, count) {
83
+ let part = "";
84
+ const put = (s) => { const r = redact(s); count.n += r.n; writeSync(fd, r.text); };
85
+ return {
86
+ push(chunk) {
87
+ part += chunk;
88
+ const i = part.lastIndexOf("\n");
89
+ if (i >= 0) { put(part.slice(0, i + 1)); part = part.slice(i + 1); }
90
+ },
91
+ end() { if (part) put(`${part}\n`); part = ""; },
92
+ };
93
+ }
94
+
95
+ const GRACE_MS = 3000;
96
+ const SIGNALS = ["SIGTERM", "SIGINT", "SIGHUP"];
97
+
98
+ function exitText(state, code, signal) {
99
+ if (state.timedOut) return `timeout(${state.timeoutS}s)`;
100
+ if (state.error) return `error(${state.error})`;
101
+ return code === null || code === undefined ? `signal(${signal})` : String(code);
102
+ }
103
+
104
+ // Closes the log once: on close, a little after exit when a descendant still holds the pipes, or on a signal
105
+ // to this helper (the child's tree is ended first).
106
+ function closer(state, fd, sinks, child, done) {
107
+ return (code, signal, how) => {
108
+ if (state.ended) return;
109
+ state.ended = true;
110
+ clearTimeout(state.timer); clearTimeout(state.grace);
111
+ for (const s of SIGNALS) process.removeListener(s, state.onSignal);
112
+ sinks.forEach((s) => s.end());
113
+ if (how === "orphan") { killTree(child.pid); child.stdout.destroy(); child.stderr.destroy(); }
114
+ const exit = how === "interrupted" ? `interrupted(${signal})` : exitText(state, code, signal);
115
+ writeSync(fd, `${how === "orphan" ? "# orphan-output=yes\n" : ""}# redacted=${state.count.n}\nexit=${exit}\n`);
116
+ closeSync(fd);
117
+ appendFileSync(state.file, runMetrics(readFileSync(state.file, "utf8"), exit).map((m) => `METRIC ${m}\n`).join(""));
118
+ done({ file: state.file, code: state.timedOut ? 124 : typeof code === "number" ? code : 1, exit });
119
+ };
120
+ }
121
+
122
+ export async function runLogged({ log, argv, cwd = process.cwd(), timeoutS = 300, shell = false }) {
123
+ if (!argv.length) throw new Usage("실행할 명령이 없음(-- 뒤에 씀)");
124
+ const file = claimLog(log);
125
+ const fd = openSync(file, "wx");
126
+ writeSync(fd, header(argv, shell, cwd));
127
+ const [cmd, args] = spawnArgs(argv, shell);
128
+ return new Promise((done) => {
129
+ const state = { file, timeoutS, count: { n: 0 }, ended: false, timedOut: false, error: null, timer: null, grace: null, onSignal: null };
130
+ const sinks = [lineSink(fd, state.count), lineSink(fd, state.count)];
131
+ const child = spawn(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32", windowsHide: true });
132
+ const finish = closer(state, fd, sinks, child, done);
133
+ state.onSignal = (sig) => { killTree(child.pid); finish(null, sig, "interrupted"); process.exit(130); };
134
+ for (const s of SIGNALS) process.once(s, state.onSignal);
135
+ state.timer = setTimeout(() => {
136
+ state.timedOut = true;
137
+ killTree(child.pid);
138
+ state.grace = setTimeout(() => finish(null, "SIGKILL", "orphan"), GRACE_MS);
139
+ }, timeoutS * 1000);
140
+ child.stdout.setEncoding("utf8").on("data", (c) => sinks[0].push(c));
141
+ child.stderr.setEncoding("utf8").on("data", (c) => sinks[1].push(c));
142
+ child.on("error", (e) => { state.error = e.code || e.message; finish(null, null); });
143
+ child.on("exit", (code, signal) => { state.grace = setTimeout(() => finish(code, signal, "orphan"), GRACE_MS); });
144
+ child.on("close", (code, signal) => finish(code, signal));
145
+ });
146
+ }
147
+
148
+ // Test counts the common runners print, so a document can cite them: node --test (spec and TAP), pytest, jest.
149
+ const SUMMARIES = [
150
+ [/^\S*\s*(?:ℹ|#) (tests|pass|fail|skipped|todo|cancelled) (\d+)\s*$/gm, (m) => [[m[1], m[2]]]],
151
+ [/^=+ (.*\b(?:passed|failed)\b.*) in [\d.]+s/gm, (m) => [...m[1].matchAll(/(\d+) (passed|failed|skipped|errors?|xfailed|xpassed)/g)].map((x) => [x[2], x[1]])],
152
+ [/^Tests:\s+(.*\btotal)\s*$/gm, (m) => [...m[1].matchAll(/(\d+) (passed|failed|skipped|todo|total)/g)].map((x) => [x[2], x[1]])],
153
+ ];
154
+
155
+ export function runMetrics(text, exit) {
156
+ const out = new Map([["run.exit", exit]]);
157
+ for (const [re, pick] of SUMMARIES) for (const m of text.matchAll(re)) for (const [k, v] of pick(m)) out.set(`run.tests.${k}`, v);
158
+ return [...out].map(([k, v]) => `${k}=${v}`);
159
+ }
160
+
161
+ // ---- long-running servers -------------------------------------------------------------------------------------
162
+
163
+ async function reachable(url) {
164
+ try {
165
+ await fetch(url, { signal: AbortSignal.timeout(2000) });
166
+ return true;
167
+ } catch {
168
+ return false;
169
+ }
170
+ }
171
+
172
+ async function waitReady(child, ready, waitS) {
173
+ const end = Date.now() + waitS * 1000;
174
+ while (Date.now() < end) {
175
+ if (child.exitCode !== null || child.signalCode !== null) return `not-ready(exited ${child.exitCode ?? child.signalCode})`;
176
+ if (await reachable(ready)) return null;
177
+ await new Promise((r) => setTimeout(r, 500));
178
+ }
179
+ return `not-ready(${waitS}s)`;
180
+ }
181
+
182
+ export async function serve({ log, pidFile, ready, waitS = 60, argv, cwd = process.cwd(), shell = false }) {
183
+ if (!argv.length) throw new Usage("실행할 명령이 없음(-- 뒤에 씀)");
184
+ if (existsSync(pidFile)) throw new Error(`pid 파일이 이미 있음: ${pidFile} (먼저 stop)`);
185
+ if (await reachable(ready)) throw new Error(`이미 답하는 서버가 있음: ${ready} (띄우지 않음. 이미 떠 있던 서버로 다룸)`);
186
+ const file = claimLog(log);
187
+ const fd = openSync(file, "wx");
188
+ writeSync(fd, header(argv, shell, cwd));
189
+ const [cmd, args] = spawnArgs(argv, shell);
190
+ const child = spawn(cmd, args, { cwd, stdio: ["ignore", fd, fd], detached: true, windowsHide: true });
191
+ closeSync(fd);
192
+ writeFileSync(pidFile, `${child.pid}\n${file}\n`);
193
+ const why = await waitReady(child, ready, waitS);
194
+ child.unref();
195
+ if (!why) return { file, pid: child.pid, ready: true };
196
+ stop({ pidFile, why });
197
+ return { file, pid: child.pid, ready: false, why };
198
+ }
199
+
200
+ // Ends the server's process tree, masks the secrets its log may hold and closes the log with its exit line.
201
+ export function stop({ pidFile, why: given = "stopped" }) {
202
+ let why = given;
203
+ const [pid, file] = lines(readFileSync(pidFile, "utf8"));
204
+ let alive = true;
205
+ try { process.kill(Number(pid), 0); } catch (e) { alive = e.code === "EPERM"; }
206
+ if (!alive && why === "stopped") why = "gone-before-stop";
207
+ killTree(Number(pid));
208
+ if (file && existsSync(file)) {
209
+ const r = redact(readFileSync(file, "utf8"));
210
+ writeFileSync(file, `${r.text}${r.text.endsWith("\n") ? "" : "\n"}# redacted=${r.n}\nexit=${why}\n`);
211
+ }
212
+ rmSync(pidFile, { force: true });
213
+ return { pid: Number(pid), file };
214
+ }
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * gate-evidence: a gate command run by this program, not by the model, and what it saw, as the evidence ralph-qa
4
- * (--gates), ultraqa, all-in-one, ultra-init and ultra-chain judge by. The source of truth is
5
- * skills/ralph-qa/references/gate-evidence.mjs; skills/ultraqa/references holds a byte-identical copy
6
- * (scripts/sync-adapter.js).
4
+ * (--gates), ultraqa, the Codex ralph, all-in-one, ultra-init and ultra-chain judge by. The source of truth is
5
+ * skills/ralph-qa/references/gate-evidence.mjs; skills/ultraqa/references and codex/skills/ralph/scripts hold
6
+ * byte-identical copies (scripts/sync-adapter.js).
7
7
  *
8
8
  * node gate-evidence.mjs init [--cwd <repo>] the gate folder <g> of one ralph-qa run (ralph-qa-gates.<letters and digits>): made
9
9
  * once before the baseline, kept across the iterations, apart from the payload folder seat-run.mjs makes anew
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * run-folder: the private run folders of ralph-qa and ultraqa, and the work tree snapshot their gate evidence is judged
4
- * against. The source of truth is skills/ralph-qa/references/run-folder.mjs; skills/ultraqa/references holds a
5
- * byte-identical copy (scripts/sync-adapter.js).
3
+ * run-folder: the private run folders of ralph-qa, ultraqa and the Codex ralph, and the work tree snapshot their gate
4
+ * evidence is judged against. The source of truth is skills/ralph-qa/references/run-folder.mjs;
5
+ * skills/ultraqa/references and codex/skills/ralph/scripts hold byte-identical copies (scripts/sync-adapter.js).
6
6
  *
7
7
  * bases(ctx) { base, known }: this run's base, and every base a run of any version used
8
8
  * sharedAbove(p) the nearest folder above p every account may write in, or null (POSIX)
@@ -60,7 +60,7 @@ ultra-chain 이 직접 하는 일은 여섯 가지다.
60
60
  | 1 전문가 작업 방식 | `Skill("banker:lfm")` | `$banker-lfm` |
61
61
  | 2 모호성 제거 | `Skill("banker:ultra-interview")` | `$banker-ultra-interview` |
62
62
  | 3 합의 계획 | `Skill("oh-my-claudecode:ralplan")` `--deliberate`, 이어서 `Skill("banker:ralph-qa")` | `$ralplan --deliberate`, 이어서 `$banker-ralph-qa`(플러그인 길 `$banker:ralph-qa`) |
63
- | 5 구현 | `Skill("oh-my-claudecode:ralph")` `--critic=critic`, 이어서 이 스킬의 critic 좌석 `<agents>` 개 루프 | `$ralph`, 이어서 이 스킬의 critic 좌석 `<agents>` 개 루프(OMX `ralph` 에는 `--critic` 이 없다) |
63
+ | 5 구현 | `Skill("oh-my-claudecode:ralph")` `--critic=critic`, 이어서 이 스킬의 critic 좌석 `<agents>` 개 루프 | banker `$banker-ralph`(플러그인 길 `$banker:ralph`), 이어서 이 스킬의 critic 좌석 `<agents>` 개 루프(banker `ralph` 에는 `--critic` 이 없다. OMX 0.21 이 `$ralph` 를 없앰) |
64
64
  | 5 critic 좌석 에이전트 | `Agent` 의 `Plan` 유형, `model` 없이 | `spawn_agent`, 역할 규칙은 아래 |
65
65
  | 6 합의 검증 | `Skill("banker:ralph-qa")` | `$banker-ralph-qa`(플러그인 길 `$banker:ralph-qa`) |
66
66
  | 7 시각 판정 에이전트 | 판정자 `<agents>` 명. `Plan` 유형, `model` 없이 | 판정자 `<agents>` 명. `spawn_agent`, 역할과 `model` 없이 |
@@ -70,11 +70,11 @@ ultra-chain 이 직접 하는 일은 여섯 가지다.
70
70
  | 이어 하기 메모 | OMC 작업 노트에 덧붙이기(`notepad_write_working`). 우선 노트는 통째로 바뀌므로 쓰지 않음 | `.omx/notepad.md` 에 한 줄 덧붙이기 |
71
71
  | 실행 기록 기본 폴더 | `.omc/ultra-chain/` | `.omx/ultra-chain/` |
72
72
 
73
- - Codex 에는 Skill 도구가 없다. 위 표의 `$이름` 은 그 스킬의 `SKILL.md` 를 읽고 그대로 따른다는 뜻이다. banker 스킬은 npm 설치면 `<S>/../banker-<이름>/SKILL.md`, Codex 플러그인 설치(`<S>` 가 `plugins/cache/` 아래, 스킬 이름 `banker:<이름>`)면 `<S>/../<이름>/SKILL.md` 다. 표의 `$banker-<이름>` 은 플러그인 설치에서 `$banker:<이름>` 이다. OMX 스킬은 `~/.codex/skills/<이름>/SKILL.md` 다. 그 스킬이 상태 기록을 요구하면 그 지시대로 직접 기록한다. 큰 `SKILL.md`(ralph-qa 는 약 71KB)는 셸 출력 한도에서 잘리니 나눠 읽는다.
73
+ - Codex 에는 Skill 도구가 없다. 위 표의 `$이름` 은 그 스킬의 `SKILL.md` 를 읽고 그대로 따른다는 뜻이다. banker 스킬은 npm 설치면 `<S>/../banker-<이름>/SKILL.md`, Codex 플러그인 설치(`<S>` 가 `plugins/cache/` 아래, 스킬 이름 `banker:<이름>`)면 `<S>/../<이름>/SKILL.md` 다. 표의 `$banker-<이름>` 은 플러그인 설치에서 `$banker:<이름>` 이다. Codex 전용인 banker `ralph` 만 플러그인 설치에서 `<S>/../../codex/skills/ralph/SKILL.md` 다(npm 설치는 `<S>/../banker-ralph/SKILL.md`). OMX 스킬은 `~/.codex/skills/<이름>/SKILL.md` 다. 그 스킬이 상태 기록을 요구하면 그 지시대로 직접 기록한다. 큰 `SKILL.md`(ralph-qa 는 약 71KB)는 셸 출력 한도에서 잘리니 나눠 읽는다.
74
74
  - Codex 의 하위 에이전트(critic 좌석, 시각 판정자)는 저자 대화를 넘기지 않는다. multi-agent v2 는 `fork_turns="none"` 을 주고, v1 은 `fork_context` 를 주지 않는다. 판정을 받으면 `close_agent` 로 닫는다.
75
75
  - Codex 의 동시 하위 에이전트 한도보다 `<agents>` 가 크면 나눠 띄우고, 모두 받은 뒤 합친다.
76
76
  - Codex 환경 지시가 역할(`agent_type`)을 요구하면, 고정 모델이 세션 모델과 같은 역할을 쓰고 지시 앞머리에 파일 쓰기 금지를 적는다. 그런 역할이 없으면 역할 없이 띄운다. 쓴 역할과 모델, 강도를 판정 기록의 `note` 에 적는다.
77
- - **Codex 의 tmux 밖 실행.** OMX 의 런타임 워크플로(`ralph`, `team` 등)는 OMX tmux 런타임을 요구한다. OMX 의 `AGENTS.md` 는 tmux 밖(Codex App, 일반 `codex`, `codex exec`)이면 그 사실을 알리고 가장 가까운 대체 경로로 계속하라고 정한다(oh-my-codex 0.20.2 `templates/AGENTS.md`). 그래서 tmux 밖이라는 사실만으로는 멈추지 않는다. 그 단계는 이 세션이 그 스킬의 `SKILL.md` 절차를 네이티브 하위 에이전트로 그대로 따르고, 보고에 `<단계>: tmux 밖 대체 실행(OMX 런타임 없음)` 한 줄을 적는다. 종결 낱말은 다른 멈춤 조건과 마지막 ralph-qa 판정으로만 정한다. 대체 실행도 할 수 없으면(하위 에이전트 기능이 꺼짐 등) `STOPPED(omx-runtime-unavailable)` 로 멈추고 tmux 안의 OMX 에서 다시 실행하라고 안내한다.
77
+ - **Codex 의 tmux 밖 실행.** banker `ralph` 는 tmux 가 필요 없다. OMX 의 런타임 워크플로(`team` 등)는 OMX tmux 런타임을 요구한다. OMX 의 `AGENTS.md` 는 tmux 밖(Codex App, 일반 `codex`, `codex exec`)이면 그 사실을 알리고 가장 가까운 대체 경로로 계속하라고 정한다(oh-my-codex 0.20.2 `templates/AGENTS.md`). 그래서 tmux 밖이라는 사실만으로는 멈추지 않는다. 그 단계는 이 세션이 그 스킬의 `SKILL.md` 절차를 네이티브 하위 에이전트로 그대로 따르고, 보고에 `<단계>: tmux 밖 대체 실행(OMX 런타임 없음)` 한 줄을 적는다. 종결 낱말은 다른 멈춤 조건과 마지막 ralph-qa 판정으로만 정한다. 대체 실행도 할 수 없으면(하위 에이전트 기능이 꺼짐 등) `STOPPED(omx-runtime-unavailable)` 로 멈추고 tmux 안의 OMX 에서 다시 실행하라고 안내한다.
78
78
  - Codex 의 오래 도는 명령은 기다리는 시간을 박스 `--timeout` 보다 길게 둔다. 기다리다 끊기면 박스 정리와 결과 JSON 이 남지 않는다.
79
79
  - Codex 세션을 닫으면 그 세션에서 띄운 서버도 끝날 수 있다. 오래 볼 미리보기는 사용자 터미널에서 띄우게 안내한다(9단계).
80
80
 
@@ -241,6 +241,7 @@ ralplan 은 계획 작성자 외에 Architect 와 Critic 두 검토자로 합의
241
241
  - 계획에 `## 전문가 작업 방식 적용` 절을 두라는 지시. `01-masters.md` 의 `M-n` 마다 판정(적용, 조정, 제외)과 계획의 어느 단계에 넣었는지, 조정과 제외는 그 이유를 적는다. 판정을 바꾸면(예: `lfm` 이 적용인데 계획은 제외) 이유를 적는다
242
242
  - 계획 저장 경로: Claude Code 는 `.omc/plans/ultra-chain-<run id>.md`. Codex 는 OMX 규칙대로 `.omx/plans/` 에 쓴다
243
243
  - Codex: 인터뷰가 끝났으니 `$deep-interview` 를 돌리지 말라는 말
244
+ - Codex: 계획만 쓰고 멈추라는 말. OMX 0.21 의 `$ralplan` 은 끝에 스스로 `$ultragoal` 로 넘어간다. `$ultragoal`, `$ralph`, `$team`, 구현으로 넘어가지 않게 한다
244
245
  - 계획에 넣을 것
245
246
  - 대상 OS 와 OS 별 시험 명령. 비대화형으로 돌게 한다(`CI=true`, 감시 모드 끔. Windows 는 `cmd` 기준으로 `set CI=true&&`)
246
247
  - 시험 출력 꼴. node:test 면 TAP(`--test-reporter=tap`)로 내게 한다. 박스 결과가 시험 수를 셀 수 있다
@@ -336,7 +337,13 @@ ralplan 은 계획 작성자 외에 Architect 와 Critic 두 검토자로 합의
336
337
  - `prd.json` 이 없으면 OMC 의 `PRD` 꼴(`src/hooks/ralph/prd.ts`)로 쓴다. 최상위 `project`(저장소 이름), `branchName`(지금 브랜치), `description`(작업 요약), `userStories` 는 빠지면 OMC 가 PRD 전체를 무효로 읽는다. 이야기마다 `id`, `title`, `description`, `acceptanceCriteria`(배열), `priority`(수), `passes: false` 를 넣는다. 위에서 정한 피드백 명령은 `feedbackCommands`, 품질 등급은 `repoQualityClass` 로 같은 파일에 넣는다. 빠지면 `omc ralph verify` 가 package.json 의 스크립트로 대신 돈다.
337
338
  - OMC 의 내부 모듈(`dist/` 아래)을 불러 PRD 나 상태를 만들지 않는다. 판이 다른 내부 API 를 부르게 된다. 이 확인과 고친 것을 `build` 의 `note` 에 적는다.
338
339
  3. ralph 가 끝까지 가게 둔다(검토자 승인, deslop, 회귀 확인, `/oh-my-claudecode:cancel`). ralph 의 cancel 은 구현 단계의 끝이지 연쇄의 끝이 아니다. ralph 가 아직 도는 동안 6단계를 시작하지 않는다. 끝나면 `.omc/state/sessions/<id>/prd.json`(`OMC_STATE_DIR` 이 있으면 그 아래)을 `<run>/05-prd.json` 으로 복사한다. ralph 의 반복 한도는 ralph 자신의 것이다. ralph 보고에서 실제로 승인한 검토자가 critic 인지 확인해 기록한다. Skill 경로로 켠 ralph 는 검토자 설정이 architect 로 남을 수 있다. ralph 의 승인은 `build` 에 `note` 하나로 `verdict.by: "ralph-reviewer"` 로 기록한다(좌석 수 검사 대상이 아니다). 이어서 5의 critic 좌석 루프를 돈다.
339
- 4. Codex: `$ralph` 를 따른다. 2의 입력을 같이 넘기고, 인터뷰가 끝났으니 `$deep-interview` 를 돌리지 말라고 적는다. 연쇄 전체의 목표(goal)를 완료로 바꾸지 말라고도 적는다. ralph 의 승인은 3과 같이 `verdict.by: "ralph-reviewer"` 로 기록한다. 이어서 5의 critic 좌석 루프를 돈다.
340
+ 4. Codex: banker `$banker-ralph`(플러그인 길 `$banker:ralph`)를 따른다. OMX 의 `$ralph` 는 부르지 않는다(OMX 0.21 이 없앰).
341
+ - 2의 입력 가운데 계획, 목업, 기대 출력, 수용 기준을 넘긴다. `repoQualityClass`, `prd.json`, `state_read` 는 Claude Code 의 OMC 것이라 넘기지 않는다
342
+ - 게이트: 계획의 로컬 게이트 목록(게이트마다 명령 하나와 시간 제한)을 넘긴다. 2의 피드백 명령 꼴(`grep -Ev` 로 거른 꼴)이 아니라 종료 코드로 판정하는 보통 명령을 쓴다
343
+ - 인터뷰가 끝났으니 `$deep-interview` 를 돌리지 말라고 적는다. 연쇄 전체의 목표(goal)를 완료로 바꾸지 말라고도 적는다. 질문하지 말고 가정을 적으라고 적는다
344
+ - ralph 가 `RALPH COMPLETE` 줄을 낸 뒤에만 다음으로 간다. `RALPH STOPPED` 면 그 까닭으로 `stopped` 를 기록하고 멈춘다
345
+ - ralph 의 게이트 폴더는 이 연쇄의 `<g>` 와 따로다. ralph 가 끝나며 지운다. ralph 의 `RALPH COMPLETE` 줄을 `build` 의 `note` 에 적는다
346
+ - ralph 의 승인은 3과 같이 `verdict.by: "ralph-reviewer"` 로 기록한다. 이어서 5의 critic 좌석 루프를 돈다
340
347
  5. critic 좌석 루프(두 런타임 공통). ralph 의 critic 은 1명 고정이고 ralph 가 끝나면 다시 판정할 수 없어서, ralph 가 끝난 뒤 이 스킬의 좌석 `<agents>` 개로 다시 판정한다.
341
348
  - 좌석 `critic#1`..`critic#<agents>` 를 런타임 대응 표의 5 critic 좌석 에이전트로 띄운다. Claude Code 는 `Agent` 의 `Plan` 유형을 `model` 없이(읽기 전용 도구, 세션 모델) 쓴다. Codex 는 `spawn_agent` 이고, 역할 `critic` 의 고정 모델이 세션 모델과 같으면 그 역할을 쓰고, 아니면 런타임 대응 절의 역할 규칙을 따른다. 지시 앞머리에 파일 쓰기 금지를 적는다.
342
349
  - Agent 도구나 `Plan` 유형을 띄울 수 없으면(Codex 는 하위 에이전트 기능이 꺼짐) 한 맥락이 좌석을 연기하지 않는다. 그 회차를 `INCONCLUSIVE` 로 기록하고 멈춘다(ralph-qa 의 "띄울 수 없으면 흉내 내지 않는다" 와 같은 규칙).
@@ -38,7 +38,7 @@ So the effective order is `ralplan → ralph → QA gate`. This is intentional,
38
38
  <Loop_Authority_Rules>
39
39
  Several bundled skills are loop/persistence engines. To prevent competing loops, **only ONE loop authority is active at a time, and the phases run strictly sequentially** (a phase fully completes before the next begins):
40
40
 
41
- 1. In **Phase 2, ralph is the sole loop authority** ("the boulder never stops"). Let its loop run to completion. Do **NOT** arm a Claude Code `/goal` Stop-hook loop beside it.
41
+ 1. In **Phase 2, ralph is the sole loop authority** ("the boulder never stops" in Claude Code; on Codex banker's `ralph` Stop hook keeps the turn going). Let its loop run to completion. Do **NOT** arm a Claude Code `/goal` Stop-hook loop beside it.
42
42
  2. **The QA gate runs only in Phase 3, AFTER ralph has finished**, as the terminal QA sub-gate — never concurrently with ralph. banker's `ralph-qa` owns that judge → fix loop on both runtimes; ultra-init owns no loop.
43
43
  3. **There is no ultrawork phase.** OMC 5.0.0 retired `ultrawork`; ralph's own parallel delegation covers it inside Phase 2.
44
44
  </Loop_Authority_Rules>
@@ -53,19 +53,20 @@ Several bundled skills are loop/persistence engines. To prevent competing loops,
53
53
  omc ralph verify --help 2>&1 | grep -q 'Usage: omc ralph verify' && echo "omc ok" || echo "omc CLI missing or too old"
54
54
  ```
55
55
  If the check fails, **guide installation or update first** via `/banker:setup` → oh-my-claudecode (or the `setup-omc` skill / `npm install -g oh-my-claude-sisyphus@latest`), then resume once it passes. There is no way around a missing or stale CLI: ralph itself stops without `omc ralph verify`, so do not start Phase 1.
56
- - **런타임 매핑 (Claude Code ↔ Codex).** `ralplan`·`ralph`·`cancel` 은 Claude Code에선 OMC, **Codex에선 oh-my-codex(OMX)가 제공하는 동명 스킬**이다(Codex는 `omx setup` 전제, 점검은 `omx --version`). OMX 의 `ralph` 는 `omc` CLI 를 쓰지 않으므로 위 `omc` 점검은 Claude Code 에만 해당한다. Phase 3 QA 게이트는 두 런타임 모두 banker `ralph-qa` 다: Claude Code `Skill("banker:ralph-qa")`, Codex npm 길 `$banker-ralph-qa`, 플러그인 길 `$banker:ralph-qa`. Codex 에는 Skill 도구가 없으니 그 `SKILL.md` 를 읽고 그대로 따른다(npm 길 `<S>/../banker-ralph-qa/SKILL.md`, 플러그인 길 `<S>/../ralph-qa/SKILL.md`, `<S>` 는 이 스킬 폴더). `<RQ>` 는 ralph-qa 의 `references` 폴더다(Claude Code 와 Codex 플러그인 길 `<S>/../ralph-qa/references`, Codex npm 길 `<S>/../banker-ralph-qa/references`). 아래 Phase들의 `Skill("oh-my-claudecode:<name>")` 표기는 Claude Code 기준 — **Codex 런타임에선 OMX의 해당 스킬을 적용**한다.
57
- - **Codex 의 tmux 밖 실행.** OMX 의 런타임 워크플로(`ralph`, `team` 등)는 OMX tmux 런타임을 요구한다. OMX 의 `AGENTS.md` 는 tmux 밖(Codex App, 일반 `codex`, `codex exec`)이면 그 사실을 알리고 가장 가까운 대체 경로로 계속하라고 정한다(oh-my-codex 0.20.2 `templates/AGENTS.md`). 그래서 tmux 밖이라는 사실만으로는 멈추지 않는다. 그 단계는 이 세션이 그 스킬의 `SKILL.md` 절차를 네이티브 하위 에이전트로 그대로 따르고, 보고에 `<단계>: tmux 밖 대체 실행(OMX 런타임 없음)` 한 줄을 적는다. 종결 낱말은 다른 멈춤 조건과 마지막 ralph-qa 판정으로만 정한다. 대체 실행도 할 수 없으면(하위 에이전트 기능이 꺼짐 등) `STOPPED(omx-runtime-unavailable)` 로 멈추고 tmux 안의 OMX 에서 다시 실행하라고 안내한다.
58
- - **Codex 의 계획과 상태 경로.** 이 문서의 `.omc/plans/`, `.omc/state/sessions/<id>/prd.json` 은 Claude Code(OMC) 경로다. Codex 에서는 OMX 경로를 쓴다: 계획은 `.omx/plans/`(ralplan 이 쓰는 `prd-*.md`, `test-spec-*.md`), ralph 의 진행 기록은 `.omx/state/<scope>/ralph-progress.json`. Codex 에서 `.omc/` 아래에 계획을 쓰지 않는다.
56
+ - **런타임 매핑 (Claude Code ↔ Codex).** `ralplan`·`cancel` 은 Claude Code에선 OMC, **Codex에선 oh-my-codex(OMX)가 제공하는 동명 스킬**이다(Codex는 `omx setup` 전제, 점검은 `omx --version`). `ralph` 는 Claude Code에선 OMC, **Codex에선 banker 의 Codex 전용 `ralph`** 다(npm 길 `$banker-ralph`, 플러그인 길 `$banker:ralph`, `SKILL.md` 는 npm 길 `<S>/../banker-ralph/SKILL.md`, 플러그인 길 `<S>/../../codex/skills/ralph/SKILL.md`). OMX 0.21 이 `$ralph` 를 없앴으므로 OMX 의 `$ralph` 는 부르지 않는다. banker `ralph` 는 OMX 와 `omc` CLI 를 쓰지 않으므로 위 `omc` 점검은 Claude Code 에만 해당한다. Phase 3 QA 게이트는 두 런타임 모두 banker `ralph-qa` 다: Claude Code `Skill("banker:ralph-qa")`, Codex npm 길 `$banker-ralph-qa`, 플러그인 길 `$banker:ralph-qa`. Codex 에는 Skill 도구가 없으니 그 `SKILL.md` 를 읽고 그대로 따른다(npm 길 `<S>/../banker-ralph-qa/SKILL.md`, 플러그인 길 `<S>/../ralph-qa/SKILL.md`, `<S>` 는 이 스킬 폴더). `<RQ>` 는 ralph-qa 의 `references` 폴더다(Claude Code 와 Codex 플러그인 길 `<S>/../ralph-qa/references`, Codex npm 길 `<S>/../banker-ralph-qa/references`). 아래 Phase들의 `Skill("oh-my-claudecode:<name>")` 표기는 Claude Code 기준 — **Codex 런타임에선 OMX의 해당 스킬을 적용**한다(`ralph` 만 banker `ralph`).
57
+ - **Codex 의 tmux 밖 실행.** banker `ralph` 는 tmux 가 필요 없다. OMX 의 런타임 워크플로(`team` 등)는 OMX tmux 런타임을 요구한다. OMX 의 `AGENTS.md` 는 tmux 밖(Codex App, 일반 `codex`, `codex exec`)이면 그 사실을 알리고 가장 가까운 대체 경로로 계속하라고 정한다(oh-my-codex 0.20.2 `templates/AGENTS.md`). 그래서 tmux 밖이라는 사실만으로는 멈추지 않는다. 그 단계는 이 세션이 그 스킬의 `SKILL.md` 절차를 네이티브 하위 에이전트로 그대로 따르고, 보고에 `<단계>: tmux 밖 대체 실행(OMX 런타임 없음)` 한 줄을 적는다. 종결 낱말은 다른 멈춤 조건과 마지막 ralph-qa 판정으로만 정한다. 대체 실행도 할 수 없으면(하위 에이전트 기능이 꺼짐 등) `STOPPED(omx-runtime-unavailable)` 로 멈추고 tmux 안의 OMX 에서 다시 실행하라고 안내한다.
58
+ - **Codex 의 계획과 상태 경로.** 이 문서의 `.omc/plans/`, `.omc/state/sessions/<id>/prd.json` 은 Claude Code(OMC) 경로다. Codex 에서는 OMX 경로를 쓴다: 계획은 `.omx/plans/`(ralplan 이 쓰는 `prd-*.md`, `test-spec-*.md`), ralph 의 진행 기록은 저장소 밖 게이트 폴더의 `ralph.md`(banker `ralph` 의 `ralph-state.mjs`). Codex 에서 `.omc/` 아래에 계획을 쓰지 않는다.
59
59
 
60
60
  ### Phase 1 — PLAN: ralplan --deliberate (합의 계획)
61
61
  - Invoke `Skill("oh-my-claudecode:ralplan")` with `--deliberate <brief>` in **non-interactive** mode (so it produces the consensus-approved plan, marks it `pending approval`, and **stops without launching team/ralph itself** — ultra-init controls the hand-off).
62
+ - **Codex: plan only.** OMX 0.21's `$ralplan` ends by moving on to `$ultragoal`. Tell it to write the plan and stop there: no `$ultragoal`, `$ralph`, `$team` or implementation. Phase 2 is banker's `ralph`.
62
63
  - ralplan runs **Planner → Architect → Critic** to consensus (max 5 iterations), and in deliberate mode adds a **pre-mortem (3 scenarios) + expanded test plan (unit/integration/e2e/observability)**.
63
64
  - Capture the final plan and its path in `.omc/plans/`: **ADR + ordered user stories + per-story testable acceptance criteria + the test plan**. This is the seed for Phases 2–3 and the durable record of the run.
64
65
  - Autonomy: treat the consensus-approved plan as approved-for-execution and continue. (`--gated` → pause here for user approval, then continue.)
65
66
 
66
67
  ### Before Phase 2 — record what already fails
67
68
  - Make the gate folder with `node '<RQ>/gate-evidence.mjs' init --cwd '<repo>'` (its `dir` is the gate folder `<g>`) and run each targeted QA dimension's command once on the unchanged tree, through ralph-qa's runner, as iteration 0: `node '<RQ>/gate-evidence.mjs' run --dir '<g>' --id <dimension> --cmd '<command>' --timeout <seconds> --iter 0 --cwd '<repo>'`. One command per dimension (no `&&` or `;` chains), a `--timeout` on each; `scenarios` has no baseline (its rows test the change).
68
- - This **pre-change record** (iteration 0 in `<g>/evidence.md`) is the QA gate's baseline: ralph-qa counts a failure with the same command and failure signature as not this change's (`baseline`). It covers checks outside ralph's feedback commands, and on Codex it is the only baseline (OMX `ralph` keeps none). On Codex the runner writes outside the workspace: ask for approval to run it outside the sandbox.
69
+ - This **pre-change record** (iteration 0 in `<g>/evidence.md`) is the QA gate's baseline: ralph-qa counts a failure with the same command and failure signature as not this change's (`baseline`). It covers checks outside ralph's feedback commands. On Codex banker's `ralph` keeps a baseline of its own in its own gate folder; this one is still the QA gate's. On Codex the runner writes outside the workspace: ask for approval to run it outside the sandbox.
69
70
  - Never use `git stash` or `git reset` for this; if the tree already has changes, take the record from a clean copy of HEAD (`git worktree add --detach <tmp> HEAD`, run with `--cwd <tmp>`, then `git worktree remove <tmp>`). A fresh worktree has no installed dependencies (`node_modules`, a venv): link or install them there first, and confirm the commands really ran — a record made only of "command not found" errors is no baseline. The runner writes the folder a command ran in as `<repo>` in the failure signature, so a failure in the copy and the same failure in the repo match.
70
71
  - The record lives in `<g>`; if the session may compact or end before Phase 3, put the `<g>` path in the `ready-compact` note. The gate folder lives until Phase 3 has its end word: no cleanup's day rule takes it (ralph-qa's gate folder rule).
71
72
  - **Not a git repo** (common for a new project): if `init` (or `run`) stops with `not-a-git-tree` (exit 3, nothing made or run), first check that the folder the stop names (`checked` in its JSON, an absolute path) is the target repo; if not, call it again with `--cwd '<repo>'`. Only when the target really is no git repo: the gates cannot have evidence (the work tree fingerprint sees no change). Take no baseline, and in Phase 3 hand ralph-qa no `--gates`; it then writes `게이트: 선언 없음(git 저장소 아님)` in its report and seat instructions. Never run `git init` yourself: tell the user that `git init` and a first commit make the gates work next time. The same on both runtimes (Claude Code, and Codex on the npm and the plugin route).
@@ -75,7 +76,8 @@ Several bundled skills are loop/persistence engines. To prevent competing loops,
75
76
  - **No questions mid-run:** ralph 5.6.1 asks the user once for the PRD's `repoQualityClass` (`prototype`, `production` or `library`) when the task does not say. Infer it from repo signals (CI config, test depth, published package metadata) and put it in the handoff; let ralph ask only when the signals genuinely conflict.
76
77
  - ralph first records the feedback baseline (`omc ralph verify --write-baseline`: the failures that already existed), then iterates **story-by-story**, delegating to parallel agents where stories allow, until all stories `passes: true`, followed by **reviewer verification → mandatory ai-slop-cleaner deslop → post-deslop regression re-verify**. ralph is the loop authority for this phase. Note its session id (the `<id>` in its PRD path `.omc/state/sessions/<id>/prd.json`) for a resume, and the baseline failures it reports at its closeout for the Phase 4 summary.
77
78
  - **Feedback commands must print only failures.** OMC 5.6.1's `omc ralph verify` fingerprints every output line and normalizes only `<number><unit>` durations, timestamps, `/tmp` paths and hex ids, so a summary line that changes between runs or when tests are added reads as a NEW failure (node:test's default reporter: `ℹ duration_ms 151.4`, `ℹ tests 8` — red on every run with no change). Have ralph set the PRD `feedbackCommands` before it records the baseline to forms that are constant on success and name each failure (node:test: `FORCE_COLOR=0 NODE_NO_WARNINGS=1 node --test --test-reporter=dot 2>&1 | grep -Ev '^[.X]+$'` — the variables keep color codes from slipping past the filter and process-id warnings out of the output; adapt the form on Windows). If the gate still flags only such lines, fix the commands and re-record ralph's baseline on the current tree (`omc ralph verify --write-baseline`); the pre-change record still tells old failures from new ones. Never edit the baseline file by hand; never stash or reset.
78
- - Do not interrupt on "The boulder never stops" continuations — that signal means ralph's iteration continues. Let it run to completion.
79
+ - **Codex: banker `ralph`.** Follow its `SKILL.md` (paths in Phase 0) instead of OMC `ralph`. Hand it the plan path with its stories and acceptance criteria, each targeted dimension's command as a gate (one command per gate id), `--no-deslop` if passed, and "no questions: write assumptions down". `--critic` has no Codex counterpart: ralph's fresh reviewer takes that place. It runs its own gate folder, apart from `<g>`. Go on to Phase 3 only after its `RALPH COMPLETE` line; on `RALPH STOPPED` stop and report its reason. The `repoQualityClass` and `omc ralph verify` bullets above are Claude Code only. For a resume, note its gate folder (`ralph-state.mjs find --cwd '<repo>'` lists it).
80
+ - Do not interrupt on "The boulder never stops" continuations (Claude Code) or banker ralph's Stop-hook continuations (Codex) — that signal means ralph's iteration continues. Let it run to completion.
79
81
 
80
82
  ### Phase 3 — QA GATE: banker ralph-qa (QA 순환)
81
83
  - After ralph completes, invoke ralph-qa once with `--gates=<dimensions> --lens=both`: every dimension the project supports (default `typecheck,lint,build,tests`, or the `--qa` list; `scenarios` adds adversarial scenario rows). One run covers every dimension: its gate conjunct holds only when each one does.
@@ -87,7 +89,7 @@ Several bundled skills are loop/persistence engines. To prevent competing loops,
87
89
  - This is a belt-and-suspenders gate over ralph's own regression: a final all-green check under ultra-init's authority (ralph has already finished, so there is no competing loop).
88
90
 
89
91
  ### Phase 4 — COMPLETE (완료 / 정리)
90
- - `Skill("oh-my-claudecode:cancel")` → clear ralph / mode state cleanly (don't leave stale state files).
92
+ - `Skill("oh-my-claudecode:cancel")` → clear ralph / mode state cleanly (don't leave stale state files). On Codex banker's `ralph` sets no OMX mode: there is nothing to cancel for it.
91
93
  - Emit a **concise, evidence-backed summary**: what was planned (plan path), stories delivered, files touched, reviewer verdict, deslop result, ralph-qa's verdict line with its gate block (per dimension), and the baseline failures that predate the change (the `baseline` gates and ralph's closeout list), listed apart.
92
94
  - **Resuming an interrupted run:** the plan file in `.omc/plans/` and ralph's PRD (`.omc/state/sessions/<id>/prd.json`, with its stories' `passes` flags) are the durable record. Hand both to a new `ralph` run; for a new session, prepare it with `ready-compact --hand-off`, which must also carry the `<g>` path (the pre-change record) and the first ralph session id. On resume, Phase 3 judges against the iteration-0 records in `<g>`; never run iteration 0 again on the half-changed tree, and do not judge by the baseline a new ralph records there: either would excuse regressions made before the interruption. The same goes for a resume in the same session.
93
95
 
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * gate-evidence: a gate command run by this program, not by the model, and what it saw, as the evidence ralph-qa
4
- * (--gates), ultraqa, all-in-one, ultra-init and ultra-chain judge by. The source of truth is
5
- * skills/ralph-qa/references/gate-evidence.mjs; skills/ultraqa/references holds a byte-identical copy
6
- * (scripts/sync-adapter.js).
4
+ * (--gates), ultraqa, the Codex ralph, all-in-one, ultra-init and ultra-chain judge by. The source of truth is
5
+ * skills/ralph-qa/references/gate-evidence.mjs; skills/ultraqa/references and codex/skills/ralph/scripts hold
6
+ * byte-identical copies (scripts/sync-adapter.js).
7
7
  *
8
8
  * node gate-evidence.mjs init [--cwd <repo>] the gate folder <g> of one ralph-qa run (ralph-qa-gates.<letters and digits>): made
9
9
  * once before the baseline, kept across the iterations, apart from the payload folder seat-run.mjs makes anew
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * run-folder: the private run folders of ralph-qa and ultraqa, and the work tree snapshot their gate evidence is judged
4
- * against. The source of truth is skills/ralph-qa/references/run-folder.mjs; skills/ultraqa/references holds a
5
- * byte-identical copy (scripts/sync-adapter.js).
3
+ * run-folder: the private run folders of ralph-qa, ultraqa and the Codex ralph, and the work tree snapshot their gate
4
+ * evidence is judged against. The source of truth is skills/ralph-qa/references/run-folder.mjs;
5
+ * skills/ultraqa/references and codex/skills/ralph/scripts hold byte-identical copies (scripts/sync-adapter.js).
6
6
  *
7
7
  * bases(ctx) { base, known }: this run's base, and every base a run of any version used
8
8
  * sharedAbove(p) the nearest folder above p every account may write in, or null (POSIX)
@@ -15,11 +15,16 @@ description: "프론트엔드 UI 를 레퍼런스(생성 이미지, 정적 이
15
15
 
16
16
  | 단계 | Claude Code (OMC) | Codex (OMX) |
17
17
  |---|---|---|
18
- | 구현 루프 | `Skill("oh-my-claudecode:ralph")` | OMX `$ralph` |
18
+ | 구현 루프 | `Skill("oh-my-claudecode:ralph")` | banker `$banker-ralph`(플러그인 길 `$banker:ralph`). OMX 0.21 이 `$ralph` 를 없애 OMX 것은 부르지 않음 |
19
19
  | 비주얼 판정 | `Skill("oh-my-claudecode:visual-verdict")` | OMX Visual Verdict |
20
20
  | 이미지 이해 | **Read 툴 네이티브**(이미지 직접 판독) | `vision` 에이전트 |
21
21
  | UI 레퍼런스 생성 | **Stitch**(`/banker:setup-stitch` MCP UI-gen); 없으면 **정적/라이브 URL 레퍼런스**로 폴백(생성 불요) | `$imagegen` + `omx imagegen continuation`(Stop-hook 큐) |
22
- | 아티팩트/상태 경로 | `.omc/artifacts/visual-ralph/<slug>/` | `.omx/artifacts/visual-ralph/<slug>/` · `.omx/state/sessions/` |
22
+ | 아티팩트/상태 경로 | `.omc/artifacts/visual-ralph/<slug>/` | `.omx/artifacts/visual-ralph/<slug>/` |
23
+
24
+ Codex 의 banker `ralph` 는 `SKILL.md` 를 읽고 따른다. npm 길 `<S>/../banker-ralph/SKILL.md`, 플러그인 길 `<S>/../../codex/skills/ralph/SKILL.md`(`<S>` 는 이 스킬 폴더).
25
+ - 그 ralph 는 게이트 기록, 검토, 슬롭 점검이 지금 작업 트리와 맞아야 끝난다. 저장소 안에 새로 쓰는 스샷과 판정 파일도 작업 트리를 바꾼다
26
+ - 그래서 반복마다 스샷과 Visual Verdict 를 ralph 의 슬롭 점검 기록 전에 끝낸다. 그 뒤에 새 스샷을 찍었으면 슬롭 점검 기록, 게이트, 검토를 다시 한다
27
+ - Visual Verdict 점수 `>= 90` 은 ralph 검토자에게 수용 기준으로 넘긴다
23
28
 
24
29
  생성 레퍼런스 경로가 양쪽 다 없으면(imagegen 부재) → **정적 레퍼런스 이미지나 라이브 URL을 요구**한다
25
30
  (생성 없이도 루프는 성립한다). 라이브 URL 클론은 이 스킬이 흡수한다(구 `$web-clone` 미사용).
@@ -53,7 +58,7 @@ description: "프론트엔드 UI 를 레퍼런스(생성 이미지, 정적 이
53
58
  - **생성 레퍼런스**: 위 런타임 매핑의 imagegen 경로로 UI 서술에서 생성. 프롬프트 요건: `ui-mockup`
54
59
  분류, viewport/종횡비·대상 표면, 레이아웃·계층·타이포·컬러 무드·정확한 텍스트, 로고/워터마크 금지,
55
60
  불가능한 UI 디테일·판독불가 텍스트 회피.
56
- - Codex 런타임에서 활성 Ralph 루프 중 내장 이미지 툴 호출 전엔 continuation 체크포인트를 큐잉:
61
+ - Codex 런타임에서 OMX 루프(OMX 0.20.x 의 ralph 모드 등)가 켜져 있을 때만, 내장 이미지 툴 호출 전에 continuation 체크포인트를 큐잉(banker `ralph` 는 OMX Stop 체크포인트를 쓰지 않으므로 이 단계가 없음. 이미지 생성은 구현 위임 전에 끝냄):
57
62
  `omx imagegen continuation <session> --artifact <slug> --generated-dir "$CODEX_HOME/generated_images/<session>" --work-dir ".omx/artifacts/visual-ralph/<slug>"`
58
63
  (내장 이미지 생성이 턴을 즉시 종료할 수 있어, 다음 Stop 체크포인트가 아티팩트 회수·QA를 재개.)
59
64
  - 승인된 레퍼런스는 **워크스페이스로 복사**한다(예: `.omc/artifacts/visual-ralph/<slug>/reference.png`).
@@ -109,7 +114,7 @@ Route/표면: <route 또는 컴포넌트>
109
114
  완료 전 build/lint/test 실행.
110
115
  명시 요청 없인 방향전환 금지."
111
116
  ```
112
- (Claude=`Skill("oh-my-claudecode:ralph")`, Codex=`$ralph` 에 위 지침 전달.)
117
+ (Claude=`Skill("oh-my-claudecode:ralph")`, Codex=banker `$banker-ralph`(플러그인 길 `$banker:ralph`) 에 위 지침 전달.)
113
118
 
114
119
  ## 함정
115
120
  - **승인 게이트 스킵 금지** — 러프 이미지를 진실원본으로 굳히면 방향이 틀어진다.