์‹œ๋ฆฌ์ฆˆ: oh-my-codex ์•„ํ‚คํ…์ฒ˜ ํ•ด๋ถ€

์ด ์‹œ๋ฆฌ์ฆˆ๋Š” OpenAI Codex CLI ํ™•์žฅ ๋Ÿฐํƒ€์ž„์ธ oh-my-codex(OMX)์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ํ•ด๋ถ€ํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

ํŽธ๋‚ด์šฉํ•ต์‹ฌ
0ํŽธOverview3-Plane ์•„ํ‚คํ…์ฒ˜, OMC์™€์˜ ์ฐจ์ด, ์ „์ฒด ํ๋ฆ„
1ํŽธCodex CLI FoundationCodex CLI ์ž์ฒด์˜ ๊ตฌ์กฐ์™€ ํ™•์žฅ ํฌ์ธํŠธ
2ํŽธ (๋ณธ๋ฌธ)OMX IntegrationOMX๊ฐ€ Codex์— ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋‚˜
3ํŽธSkill System์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์ •์˜ํ•˜๋‚˜
4ํŽธPrompt & Agent System์—์ด์ „ํŠธ๋Š” ๋ญ๊ณ  ์–ด๋–ป๊ฒŒ ์„ ํƒ๋˜๋‚˜
5ํŽธMCP Servers์–ด๋–ค MCP ๋„๊ตฌ๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‚˜
6ํŽธState & Lifecycle์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์œ ์ง€ํ•˜๋‚˜
7ํŽธTeam OrchestrationTeam ๋ชจ๋“œ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜
8ํŽธNative & SparkRust ๋„ค์ดํ‹ฐ๋ธŒ ๋„๊ตฌ๋Š” ๋ญ”๊ฐ€

  • OMX Integration์€ oh-my-codex๊ฐ€ Codex CLI์˜ ํ™•์žฅ ํฌ์ธํŠธ์— ์—ฐ๊ฒฐ๋˜๋Š” ํ†ตํ•ฉ ๋ฉ”์ปค๋‹ˆ์ฆ˜
  • Codex CLI๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  AGENTS.md, config.toml, ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ํ–‰๋™์„ ์ฃผ์ž…ํ•˜๋Š” non-invasive ํ†ตํ•ฉ ๋ฐฉ์‹
  • OMC์˜ Hook(stdin/stdout JSON) ๊ธฐ๋ฐ˜ ๊ฒฐ์ •๋ก ์ (Deterministic) ์ด๋ฒคํŠธ ๊ฐ€๋กœ์ฑ„๊ธฐ์™€ ๋Œ€๋น„๋˜๋Š”, LLM ํ•ด์„์— ์˜์กดํ•˜๋Š” ํ™•๋ฅ ๋ก ์ (Probabilistic) AGENTS.md ๊ธฐ๋ฐ˜ ํ‚ค์›Œ๋“œ ๋งคํ•‘ ์•„ํ‚คํ…์ฒ˜

ํ•ด๋‹น ๊ฐœ๋…์ด ํ•„์š”ํ•œ ์ด์œ 

  • 1ํŽธ์—์„œ Codex CLI์˜ ๊ตฌ์กฐ์™€ ํ™•์žฅ ํฌ์ธํŠธ(AGENTS.md, config.toml, MCP)๋ฅผ ์ดํ•ดํ–ˆ์Œ
  • ํ•˜์ง€๋งŒ **โ€œOMX๊ฐ€ ์ด ํ™•์žฅ ํฌ์ธํŠธ๋“ค์„ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€โ€**๊ฐ€ ์•„์ง ๋น ์ ธ ์žˆ์Œ
  • ์ด ํŒŒํŠธ๋Š” OMX์˜ ์„ค์น˜ ํ๋ฆ„(omx setup), ์‹คํ–‰ ๋ฐฉ์‹(omx launch), ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ธŒ๋ ˆ์ธ(AGENTS.md), ํ‚ค์›Œ๋“œ ๊ฐ์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๋‹ค๋ฃจ์–ด ๊ทธ ๊ฐ„๊ทน์„ ๋ฉ”์›€

AS-IS (OMC โ€” Claude Code ํ†ตํ•ฉ ๋ฐฉ์‹)

sequenceDiagram
    autonumber
    participant U as User
    participant HC as hooks.json
    participant KD as keyword-detector.mjs
    participant CC as Claude Code
    participant SK as Skill tool

    U->>CC: "ultrawork refactor API"
    CC->>HC: UserPromptSubmit ์ด๋ฒคํŠธ ๋ฐœ์ƒ
    HC->>KD: stdin JSON ์ „๋‹ฌ
    KD->>KD: "ultrawork" ํ‚ค์›Œ๋“œ ๊ฐ์ง€
    KD-->>HC: stdout JSON (์Šคํ‚ฌ ๋งคํ•‘ ๊ฒฐ๊ณผ)
    HC->>CC: ๊ฒฐ๊ณผ ์ฃผ์ž…
    CC->>SK: Skill("omc:ultrawork") ํ˜ธ์ถœ

TO-BE (OMX โ€” Codex CLI ํ†ตํ•ฉ ๋ฐฉ์‹)

sequenceDiagram
    autonumber
    participant U as User
    participant CX as Codex CLI
    participant AM as AGENTS.md
    participant SK as skills/ultrawork/SKILL.md

    U->>CX: "ultrawork refactor API"
    CX->>AM: ์„ธ์…˜ ์‹œ์ž‘ ์‹œ ์ง€์นจ ๋กœ๋“œ
    Note over CX,AM: AGENTS.md์— ํ‚ค์›Œ๋“œ ๋งคํ•‘ ํ…Œ์ด๋ธ” ๋‚ด์žฅ
    CX->>CX: "ultrawork" ํ‚ค์›Œ๋“œ ๊ฐ์ง€ (LLM์ด ์ง์ ‘ ํ•ด์„)
    CX->>SK: $ultrawork โ†’ SKILL.md ์ฝ๊ธฐ
    CX->>CX: ์Šคํ‚ฌ ์ง€์นจ์— ๋”ฐ๋ผ ์ž‘์—… ์ˆ˜ํ–‰

omx setup / omx launch โ€” ์‹คํ–‰ ์ฃผ์ฒด์™€ ์‹œ์ 

ํ•ต์‹ฌ: ์ด ๋‘ ๋ช…๋ น์–ด๋Š” AGENTS.md๋‚˜ LLM์ด ํŠธ๋ฆฌ๊ฑฐํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‚ฌ๋žŒ์ด ํ„ฐ๋ฏธ๋„์—์„œ ์ง์ ‘ ์ž…๋ ฅํ•˜๋Š” CLI ๋ช…๋ น์–ด๋‹ค.

OMX๋Š” npm์œผ๋กœ ์„ค์น˜๋˜๋Š” Node.js CLI ๋„๊ตฌ์ด๋ฉฐ, bin/omx.js๊ฐ€ ์ง„์ž…์ ์ด๋‹ค. src/cli/ ํ•˜์œ„์— ๊ฐ ์„œ๋ธŒ์ปค๋งจ๋“œ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์žˆ๊ณ , ์ด๋Š” 3-Plane ์•„ํ‚คํ…์ฒ˜์˜ Control Plane์— ํ•ด๋‹นํ•œ๋‹ค.

[์‚ฌ๋žŒ์ด ํ„ฐ๋ฏธ๋„์—์„œ ์ง์ ‘ ์ž…๋ ฅ]
$ omx setup      โ† ์ตœ์ดˆ 1ํšŒ, ํ™˜๊ฒฝ ๊ตฌ์„ฑ  (src/cli/setup.ts)
$ omx launch     โ† ๋งค ์„ธ์…˜, Codex CLI ๊ธฐ๋™  (src/cli/launch.ts)
Plane๋ฌด์—‡์ด ์‹คํ–‰์‹œํ‚ค๋‚˜์˜ˆ์‹œ
Control Plane์‚ฌ๋žŒ (ํ„ฐ๋ฏธ๋„ ์ง์ ‘ ์ž…๋ ฅ)omx setup, omx launch, omx team
Execution PlaneLLM (AGENTS.md ํ•ด์„ โ€” ํ™•๋ฅ ๋ก ์ )ํ‚ค์›Œ๋“œ ๊ฐ์ง€, ์Šคํ‚ฌ ์‹คํ–‰, ์œ„์ž„
State PlaneMCP ์„œ๋ฒ„ ์ž๋™ ๋™์ž‘state_write, memory_store

AGENTS.md๋Š” omx launch๋กœ Codex CLI๊ฐ€ ๊ธฐ๋™๋œ ์ดํ›„ LLM์ด ์ฝ๋Š” ํŒŒ์ผ์ด๋‹ค. omx setup/omx launch๋Š” ๊ทธ ์ด์ „์— ์‚ฌ๋žŒ์ด ์ˆ˜๋™์œผ๋กœ ์‹คํ–‰ํ•˜๋Š” ์„ ํ–‰ ์กฐ๊ฑด์ด๋‹ค.

sequenceDiagram
    autonumber
    participant H as ์‚ฌ๋žŒ (ํ„ฐ๋ฏธ๋„)
    participant CP as Control Plane (omx CLI)
    participant CX as Codex CLI (LLM)
    participant AM as AGENTS.md

    H->>CP: omx setup (์ตœ์ดˆ 1ํšŒ)
    CP->>CP: AGENTS.md ์ƒ์„ฑ, config.toml ๋“ฑ๋ก, skills/ ๋ฐฐ์น˜

    H->>CP: omx launch (๋งค ์„ธ์…˜)
    CP->>CP: agents-overlay.ts (src/hooks/) โ†’ ์„ธ์…˜ ํ•ฉ๋ณธ AGENTS.md ์ƒ์„ฑ
    Note over CP: user AGENTS.md + project AGENTS.md + ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„๋ ˆ์ด ๋จธ์ง€
    CP->>CX: codex (model_instructions_file = .omx/state/{sessionId}/AGENTS.md)
    Note over CX: ๋„ค์ดํ‹ฐ๋ธŒ AGENTS.md ์ฒด์ธ์€ ๋ฌด๋ ฅํ™”๋จ
    CX->>CX: ์„ธ์…˜ ํ•ฉ๋ณธ AGENTS.md๋ฅผ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ๋กœ ๋กœ๋“œ (1ํšŒ)
    Note over CX: ์ดํ›„ ํ‚ค์›Œ๋“œ ๊ฐ์ง€๋Š” ํ™•๋ฅ ๋ก ์ 

omx setup โ€” ์„ค์น˜ ํ๋ฆ„

omx setup์€ OMX์˜ ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ Codex CLI๊ฐ€ ์ธ์‹ํ•˜๋Š” ์œ„์น˜์— ๋ฐฐ์น˜ํ•˜๋Š” ๋ถ€ํŠธ์ŠคํŠธ๋ž˜ํ•‘ ๋ช…๋ น์–ด๋‹ค. ์†Œ์Šค๋Š” src/cli/setup.ts.

Scope ๊ฒฐ์ •: user-scope vs project-scope

ํ•ญ๋ชฉuser-scopeproject-scope
๋Œ€์ƒ์ „์—ญ (๋ชจ๋“  ํ”„๋กœ์ ํŠธ)ํŠน์ • ํ”„๋กœ์ ํŠธ๋งŒ
AGENTS.md~/.codex/AGENTS.md./.codex/AGENTS.md
Skills~/.agents/skills/./.agents/skills/
OMX ์„ค์ •~/.omx/./.omx/
Prompts~/.codex/prompts/./.codex/prompts/

์„ค์น˜๋˜๋Š” ๊ฒƒ๋“ค

graph LR
    Setup["omx setup"]

    Setup --> A["AGENTS.md ์ƒ์„ฑ/๋จธ์ง€"]
    Setup --> B["config.toml์— MCP ์„œ๋ฒ„ 5๊ฐœ ๋“ฑ๋ก"]
    Setup --> C["prompts/*.md โ†’ prompts/ ๋””๋ ‰ํ† ๋ฆฌ"]
    Setup --> D["skills/*/SKILL.md โ†’ skills/ ๋””๋ ‰ํ† ๋ฆฌ"]
    Setup --> E["๋„ค์ดํ‹ฐ๋ธŒ ์—์ด์ „ํŠธ ์„ค์ • โ†’ .omx/agents/"]

    style Setup fill:#4CAF50,color:#fff
  • AGENTS.md: ๊ธฐ์กด ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ๋จธ์ง€, ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑ
  • config.toml: 5๊ฐœ MCP ์„œ๋ฒ„(state, memory, code-intel, trace, team) ๋“ฑ๋ก
  • prompts/: 33๊ฐœ ์—ญํ• ๋ณ„ ์—์ด์ „ํŠธ ํ”„๋กฌํ”„ํŠธ ํŒŒ์ผ ๋ฐฐ์น˜
  • skills/: 35+ ์›Œํฌํ”Œ๋กœ์šฐ ์Šคํ‚ฌ์˜ SKILL.md ํŒŒ์ผ ๋ฐฐ์น˜
  • ๋„ค์ดํ‹ฐ๋ธŒ ์—์ด์ „ํŠธ ์„ค์ •: .omx/agents/์— ์—์ด์ „ํŠธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ €์žฅ

omx launch โ€” Codex๋ฅผ ์–ด๋–ค ํ”Œ๋ž˜๊ทธ๋กœ ์‹คํ–‰ํ•˜๋‚˜

omx launch๋Š” Codex CLI๋ฅผ OMX๊ฐ€ ์˜๋„ํ•œ ๋Œ€๋กœ ๋™์ž‘์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ ์ ˆํ•œ ํ”Œ๋ž˜๊ทธ์™€ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์„ธํŒ…ํ•˜์—ฌ ์‹คํ–‰ํ•˜๋Š” ๋ž˜ํผ ๋ช…๋ น์–ด๋‹ค.

ํ•ต์‹ฌ ์„ค์ •

  • model_instructions_file: agents-overlay.ts๊ฐ€ ์ƒ์„ฑํ•œ ์„ธ์…˜ ํ•ฉ๋ณธ AGENTS.md(.omx/state/{sessionId}/AGENTS.md) ๊ฒฝ๋กœ๋ฅผ ์ง€์ •. ์ด ์„ค์ •์ด ํ™œ์„ฑํ™”๋˜๋ฉด Codex CLI์˜ ๋„ค์ดํ‹ฐ๋ธŒ AGENTS.md ๊ณ„์ธต์  ๋จธ์ง€๊ฐ€ ๋ฌด๋ ฅํ™”๋˜๋ฏ€๋กœ, OMX๊ฐ€ ์ง์ ‘ user/project AGENTS.md๋ฅผ ํ•ฉ์ณ ๋„ฃ๋Š”๋‹ค.
  • CODEX_HOME: project-scope์ผ ๋•Œ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์˜ .codex/๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ์„ค์ •

์ฃผ์š” ํ”Œ๋ž˜๊ทธ

ํ”Œ๋ž˜๊ทธ๋™์ž‘
--yoloCodex full-auto ๋ชจ๋“œ (์Šน์ธ ์—†์ด ์‹คํ–‰)
--high / --xhigh์ถ”๋ก  ๋…ธ๋ ฅ(reasoning effort) ๋ ˆ๋ฒจ ์กฐ์ ˆ
--madmax์Šน์ธ ์šฐํšŒ โ€” ์‹ ๋ขฐ ํ™˜๊ฒฝ ์ „์šฉ
--sparkWorker์— ์ŠคํŒŒํฌ ๋ชจ๋ธ ์‚ฌ์šฉ
-w, --worktreeGit worktree ๊ฒฉ๋ฆฌ ๋ชจ๋“œ๋กœ ์‹คํ–‰

agents-overlay.ts โ€” ์„ธ์…˜๋ณ„ ํ•ฉ๋ณธ AGENTS.md ์ƒ์„ฑ

agents-overlay.ts๋Š” ์„ธ์…˜๋ณ„๋กœ ๊ณตํ†ต AGENTS.md + ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ํ•ฉ์นœ ์„ธ์…˜ ์ „์šฉ AGENTS.md๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ชจ๋“ˆ์ด๋‹ค. ์†Œ์Šค ์œ„์น˜๋Š” **src/hooks/agents-overlay.ts**์ด๋ฉฐ, src/cli/index.ts๊ฐ€ importํ•˜์—ฌ omx launch ๊ณผ์ •์—์„œ ํ˜ธ์ถœํ•œ๋‹ค. Node.js(Control Plane)๊ฐ€ ๊ฒฐ์ •๋ก ์ ์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค.

model_instructions_file โ€” ๊ณต์‹ ์ •์˜ (Codex ์†Œ์Šค: codex-rs/core/src/config/mod.rs)

โ€œOptional path to a file containing model instructions that will override the built-in instructions for the selected model. Users are STRONGLY DISCOURAGED from using this field, as deviating from the instructions sanctioned by Codex will likely degrade model performance.โ€

model_instructions_file์€ config.toml์˜ ํ‚ค๋กœ, Codex ๋‚ด์žฅ ๋ชจ๋ธ ์ง€์นจ์„ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜๋Š” ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•œ๋‹ค. ์šฐ์„ ์ˆœ์œ„: CLI ํ”Œ๋ž˜๊ทธ > ํ”„๋กœํŒŒ์ผ > ๋ฃจํŠธ config.

ํ•ต์‹ฌ: model_instructions_file์„ ์„ค์ •ํ•˜๋ฉด Codex CLI์˜ ๋„ค์ดํ‹ฐ๋ธŒ AGENTS.md ๊ณ„์ธต์  ํƒ์ƒ‰ยท๋จธ์ง€๊ฐ€ ๋ฌด๋ ฅํ™”๋œ๋‹ค (1ํŽธ Foundation ์ฐธ์กฐ: โ€œ--no-project-doc ๋˜๋Š” model_instructions_file๋กœ ๋น„ํ™œ์„ฑํ™”/๋Œ€์ฒด ๊ฐ€๋Šฅโ€). OMX๋Š” ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ์ฃผ์ž…ํ•˜๊ธฐ ์œ„ํ•ด ์ด ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ๊ทธ ์ˆœ๊ฐ„ ๋„ค์ดํ‹ฐ๋ธŒ ๋จธ์ง€๊ฐ€ ๊บผ์ง€๋ฏ€๋กœ OMX๊ฐ€ ์ง์ ‘ AGENTS.md๋ฅผ ์žฌ๋จธ์ง€ํ•ด์•ผ ํ•œ๋‹ค.

ํ•ญ๋ชฉmodel_instructions_fileAGENTS.md ๋„ค์ดํ‹ฐ๋ธŒ ์ฒด์ธ
์—ญํ• ์ง€์ •๋œ ๋‹จ์ผ ํŒŒ์ผ์„ ๋ชจ๋ธ ์ง€์นจ์œผ๋กœ ์‚ฌ์šฉ๊ณ„์ธต์  ํƒ์ƒ‰ยท์—ฐ๊ฒฐ(concatenate)
์„ค์ • ์‹œ๋„ค์ดํ‹ฐ๋ธŒ AGENTS.md ์ฒด์ธ ๋ฌด๋ ฅํ™”์ •์ƒ ๋™์ž‘
OMX ํ™œ์šฉ์„ธ์…˜ ํ•ฉ๋ณธ AGENTS.md ๊ฒฝ๋กœ ์„ค์ •omx setup์ด ์›๋ณธ AGENTS.md์— ์ง€์นจ ์ฃผ์ž…

์‹คํ–‰ ํ๋ฆ„ (์†Œ์Šค ํ™•์ธ: writeSessionModelInstructionsFile())

sequenceDiagram
    autonumber
    participant H as ์‚ฌ๋žŒ
    participant CLI as src/cli/index.ts
    participant AO as src/hooks/agents-overlay.ts
    participant UA as ~/.codex/AGENTS.md
    participant PA as {cwd}/AGENTS.md
    participant SF as .omx/state/{sessionId}/AGENTS.md
    participant CX as Codex CLI (LLM)

    H->>CLI: omx launch (Control Plane)
    CLI->>AO: writeSessionModelInstructionsFile() ํ˜ธ์ถœ
    AO->>UA: โ‘  user-level AGENTS.md ์ฝ๊ธฐ
    AO->>PA: โ‘ก project-level AGENTS.md ์ฝ๊ธฐ
    AO->>AO: โ‘ข project-scope ์Šคํ‚ฌ ์ค‘๋ณต ์ฐธ์กฐ ๋ผ์ธ ์ œ๊ฑฐ
    AO->>AO: โ‘ฃ โ‘  + โ‘ก concatenate (๋„ค์ดํ‹ฐ๋ธŒ ๋จธ์ง€๋ฅผ ์ง์ ‘ ์žฌ๊ตฌํ˜„)
    AO->>AO: โ‘ค + ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„๋ ˆ์ด append
    AO->>SF: โ‘ฅ ์„ธ์…˜ ํ•ฉ๋ณธ AGENTS.md ์“ฐ๊ธฐ
    CLI->>CX: codex ๊ธฐ๋™ (model_instructions_file = SF ๊ฒฝ๋กœ)
    Note over CX: ๋„ค์ดํ‹ฐ๋ธŒ AGENTS.md ์ฒด์ธ์€ ๋ฌด๋ ฅํ™”๋จ
    CX->>SF: ์„ธ์…˜ ์‹œ์ž‘ ์‹œ ํ•ฉ๋ณธ ํŒŒ์ผ ๋กœ๋“œ (1ํšŒ)
    Note over CX: ์ดํ›„ ํ‚ค์›Œ๋“œ ๊ฐ์ง€๋Š” ํ™•๋ฅ ๋ก ์  (Execution Plane)

์›๋ณธ AGENTS.md ํŒŒ์ผ๋“ค์€ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์„ธ์…˜์ด ๋๋‚˜๋ฉด .omx/state/{sessionId}/AGENTS.md๋Š” ์ •๋ฆฌ๋œ๋‹ค.

์„ธ์…˜ ์ค‘ ๋™์  ๊ฐฑ์‹  ๊ฐ€๋Šฅ ์—ฌ๋ถ€

๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. model_instructions_file๋กœ ์ง€์ •๋œ ํŒŒ์ผ์€ ์„ธ์…˜ ์‹œ์ž‘ ์‹œ 1ํšŒ ์ฝํ˜€ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์— ์‚ฝ์ž…๋œ๋‹ค. ์ดํ›„ ํŒŒ์ผ์„ ๋ณ€๊ฒฝํ•ด๋„ ์ด๋ฏธ context window์— ๋“ค์–ด๊ฐ„ ๋‚ด์šฉ์€ ๊ต์ฒด๋˜์ง€ ์•Š๋Š”๋‹ค.

์„ธ์…˜ ์‹œ์ž‘ ์‹œ
  AGENTS.md + ์˜ค๋ฒ„๋ ˆ์ด โ†’ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ (context window์— ๊ณ ์ •)

์„ธ์…˜ ์ค‘ ํŒŒ์ผ ๋ณ€๊ฒฝ
  โ†’ context window์—๋Š” ๋ฐ˜์˜ ์•ˆ ๋จ (LLM์€ ์ด๋ฏธ ์ด์ „ ๋‚ด์šฉ์œผ๋กœ ์ž‘๋™ ์ค‘)

MCP ํˆด ์ถ”๊ฐ€๋„ ๋™์ผํ•œ ์ด์œ ๋กœ ์„ธ์…˜ ์ค‘ ๋ฐ˜์˜ ๋ถˆ๊ฐ€๋‹ค. config.toml์˜ MCP ์„œ๋ฒ„ ๋ชฉ๋ก๋„ Codex CLI ๊ธฐ๋™ ์‹œ ๋กœ๋“œ๋˜๋ฏ€๋กœ, ์„ธ์…˜ ์ค‘ MCP ์„œ๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•ด๋„ ํ•ด๋‹น ์„ธ์…˜์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ๋‹ค์Œ omx launch ์‹œ ๋ฐ˜์˜๋œ๋‹ค.

๋ณ€๊ฒฝ ์œ ํ˜•์„ธ์…˜ ์ค‘ ๋ฐ˜์˜๋ฐ˜์˜ ์‹œ์ 
์˜ค๋ฒ„๋ ˆ์ด ํŒŒ์ผ ์ˆ˜์ •X๋‹ค์Œ omx launch
AGENTS.md ์ˆ˜์ •X๋‹ค์Œ omx launch
MCP ์„œ๋ฒ„ ์ถ”๊ฐ€ (config.toml)X๋‹ค์Œ omx launch
MCP ํˆด ๊ฒฐ๊ณผ (์ƒํƒœ ๊ธฐ๋ก ๋“ฑ)O์ฆ‰์‹œ (๋„๊ตฌ ํ˜ธ์ถœ ์‘๋‹ต์œผ๋กœ context์— ์ถ”๊ฐ€)

์„ธ์…˜์ด ๋๋‚˜๋ฉด ์˜ค๋ฒ„๋ ˆ์ด ์ž„์‹œ ํŒŒ์ผ์€ ์ •๋ฆฌ๋œ๋‹ค.

AGENTS.md โ€” ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ธŒ๋ ˆ์ธ

AGENTS.md๋Š” OMX์—์„œ โ€œtop-level operating contract for the workspaceโ€ ์—ญํ• ์„ ํ•˜๋Š” ํ•ต์‹ฌ ํŒŒ์ผ์ด๋‹ค. Codex CLI๋Š” ์ด ํŒŒ์ผ์„ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์˜ ์ผ๋ถ€๋กœ ๋กœ๋“œํ•˜๋ฏ€๋กœ, OMX๋Š” ์—ฌ๊ธฐ์— ๋ชจ๋“  ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋กœ์ง์„ ์ฃผ์ž…ํ•œ๋‹ค.

Guidance Schema โ€” ์ง€์นจ์˜ ๊ตฌ์กฐ

docs/guidance-schema.md์— ์ •์˜๋œ 6๊ฐœ ์„น์…˜ ๊ตฌ์กฐ:

์„น์…˜์—ญํ• 
Role & Intent์—์ด์ „ํŠธ์˜ ์—ญํ• ๊ณผ ๋ชฉ์  ์ •์˜
Operating Principlesํ–‰๋™ ์›์น™ 5๊ฐœ
Execution Protocolํ‚ค์›Œ๋“œ ๊ฐ์ง€, ์œ„์ž„ ๊ทœ์น™, ์‹คํ–‰ ์ ˆ์ฐจ
Constraints & Safety์ œ์•ฝ ์กฐ๊ฑด ๋ฐ ์•ˆ์ „ ์žฅ์น˜
Verification & Completion์ž‘์—… ์™„๋ฃŒ ๊ฒ€์ฆ ํ”„๋กœํ† ์ฝœ
Recovery & Lifecycle Overlays์žฅ์•  ๋ณต๊ตฌ ๋ฐ ์ƒ๋ช…์ฃผ๊ธฐ ์˜ค๋ฒ„๋ ˆ์ด

Operating Principles 5๊ฐœ

  1. โ€œSolve the task directly when you can do so safely and well.โ€ โ€” ์ง์ ‘ ํ•ด๊ฒฐ ์šฐ์„ 
  2. โ€œDelegate only when it materially improves quality, speed, or correctness.โ€ โ€” ์œ„์ž„์€ ์‹ค์งˆ์  ์ด์ ์ด ์žˆ์„ ๋•Œ๋งŒ
  3. โ€œKeep progress short, concrete, and useful.โ€ โ€” ์ง„ํ–‰ ๋ณด๊ณ ๋Š” ์งง๊ณ  ๊ตฌ์ฒด์ ์œผ๋กœ
  4. โ€œPrefer evidence over assumption; verify before claiming completion.โ€ โ€” ์ฆ๊ฑฐ ๊ธฐ๋ฐ˜ ๊ฒ€์ฆ
  5. โ€œUse the lightest path that preserves quality: direct action, MCP, then delegation.โ€ โ€” ๊ฒฝ๋Ÿ‰ ๊ฒฝ๋กœ ์šฐ์„  (์ง์ ‘ โ†’ MCP โ†’ ์œ„์ž„)

์ด 5๊ฐœ ์›์น™์€ ์—์Šค์ปฌ๋ ˆ์ด์…˜ ์‚ฌ๋‹ค๋ฆฌ๋ฅผ ํ˜•์„ฑํ•œ๋‹ค. ์—์ด์ „ํŠธ๋Š” ํ•ญ์ƒ ๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ๋ฐฉ๋ฒ•๋ถ€ํ„ฐ ์‹œ๋„ํ•˜๊ณ , ํ•„์š”ํ•  ๋•Œ๋งŒ ๋” ๋ฌด๊ฑฐ์šด ๋ฐฉ๋ฒ•(MCP ํ˜ธ์ถœ, ๋‹ค๋ฅธ ์—์ด์ „ํŠธ ์œ„์ž„)์œผ๋กœ ์˜ฌ๋ผ๊ฐ„๋‹ค.

Keyword Detection ํ…Œ์ด๋ธ”

AGENTS.md์— ๋‚ด์žฅ๋œ ํ‚ค์›Œ๋“œ ๋งคํ•‘ ํ…Œ์ด๋ธ”์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์—์„œ ํŠน์ • ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ์ง€ํ•˜๋ฉด ์–ด๋–ค ์Šคํ‚ฌ/์—์ด์ „ํŠธ๋ฅผ ํ™œ์„ฑํ™”ํ• ์ง€ ์ •์˜ํ•œ๋‹ค. ์ด ํ…Œ์ด๋ธ”์€ AGENTS.md ํ…œํ”Œ๋ฆฟ์— ์ •์ ์œผ๋กœ ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์œผ๋ฉฐ (์†Œ์Šค ํ™•์ธ: <keyword_detection> ์„น์…˜), keyword-registry.ts์—์„œ ๋™์  ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

ํ‚ค์›Œ๋“œ์šฐ์„ ์ˆœ์œ„๋งคํ•‘ ๋Œ€์ƒ
ralplan11ralph plan ๋ชจ๋“œ
autopilot10autopilot ์Šคํ‚ฌ
ultrawork10ultrawork ์Šคํ‚ฌ
ralph9ralph ์—์ด์ „ํŠธ
โ€ฆโ€ฆ30+ ์ถ”๊ฐ€ ํ‚ค์›Œ๋“œ

Delegation Rules & Verification Protocol

  • Delegation Rules: ์–ด๋–ค ์ž‘์—…์„ ์–ด๋–ค ์—์ด์ „ํŠธ์—๊ฒŒ ์œ„์ž„ํ• ์ง€์˜ ๊ทœ์น™
  • Verification Protocol: ์ž‘์—… ์™„๋ฃŒ ์ „ ๊ฒ€์ฆํ•ด์•ผ ํ•  ํ•ญ๋ชฉ๋“ค
  • Continuation Check: ์ž‘์—…์ด ์ •๋ง ๋๋‚ฌ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ์ตœ์ข… ์ฒดํฌ

ํ‚ค์›Œ๋“œ ๊ฐ์ง€ โ€” OMC Hook ๋ฐฉ์‹ vs OMX AGENTS.md ๋ฐฉ์‹

์ด ์ฐจ์ด๋Š” ๋‘ ์‹œ์Šคํ…œ์˜ ์•„ํ‚คํ…์ฒ˜์  ์„ฑ๊ฒฉ์„ ๊ฐ€์žฅ ์„ ๋ช…ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚ด๋Š” ์ง€์ ์ด๋‹ค.

OMC ๋ฐฉ์‹: ๊ฒฐ์ •๋ก ์ (Deterministic) Hook ํŒŒ์ดํ”„๋ผ์ธ

graph LR
    UP["UserPromptSubmit ์ด๋ฒคํŠธ"] --> HJ["hooks.json"]
    HJ --> KD["keyword-detector.mjs"]
    KD --> STDIN["stdin: JSON"]
    STDIN --> KD
    KD --> STDOUT["stdout: JSON"]
    STDOUT --> CC["Claude Code"]

    style KD fill:#e8f0fe
  • keyword-detector.mjs๊ฐ€ stdin/stdout JSON ํ”„๋กœํ† ์ฝœ๋กœ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ€๋กœ์ฑ”
  • Hook ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ง์ ‘ ํ‚ค์›Œ๋“œ๋ฅผ ํŒŒ์‹ฑํ•˜๊ณ , ๋งค์นญ ๊ฒฐ๊ณผ๋ฅผ LLM ์™ธ๋ถ€์—์„œ ๊ฐ•์ œ ์ฃผ์ž… โ†’ LLM์˜ ํ•ด์„ ์—ฌ๋ถ€์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์‹คํ–‰๋จ
  • ๊ฒฐ์ •๋ก ์ : ํ‚ค์›Œ๋“œ ๋งค์นญ ์‹œ ๋ฐ˜๋“œ์‹œ ์Šคํ‚ฌ์ด ์‹คํ–‰๋จ (LLM ํŒ๋‹จ ๋ถˆ๊ฐœ์ž…)
  • ์žฅ์ : ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋กœ์ง์œผ๋กœ ๋ณต์žกํ•œ ์กฐ๊ฑด ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • ๋‹จ์ : ๋ณ„๋„ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ์˜ค๋ฒ„ํ—ค๋“œ, ๋””๋ฒ„๊น… ์–ด๋ ค์›€

OMX ๋ฐฉ์‹: ํ™•๋ฅ ๋ก ์ (Probabilistic) AGENTS.md ๋‚ด์žฅ + LLM ์ง์ ‘ ํ•ด์„

graph LR
    AM["AGENTS.md<br>ํ‚ค์›Œ๋“œ ํ…Œ์ด๋ธ” (์ •์  ํ•˜๋“œ์ฝ”๋”ฉ)"] --> CX["Codex CLI (LLM)"]
    CX --> MATCH["ํ‚ค์›Œ๋“œ ๋งค์นญ"]
    MATCH --> SKILL["$skill โ†’ SKILL.md ๋กœ๋“œ"]

    KR["keyword-registry.ts"] -.->|"import"| KD["keyword-detector.ts<br>(ํ”„๋กœ๊ทธ๋ž˜๋ฐ์  2์ฐจ ๊ฐ์ง€)"]

    style CX fill:#fef7e0
  • AGENTS.md์— ํ‚ค์›Œ๋“œ ๋งคํ•‘ ํ…Œ์ด๋ธ”์ด ๋งˆํฌ๋‹ค์šด ํ…์ŠคํŠธ๋กœ ์ •์  ํ•˜๋“œ์ฝ”๋”ฉ (<keyword_detection> ์„น์…˜)
  • Codex CLI์˜ LLM์ด ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ์ฝ๊ณ  ์ง์ ‘ ํ‚ค์›Œ๋“œ๋ฅผ ํ•ด์„ โ†’ ๊ฐ•์ œ ์ฃผ์ž… ์ฑ„๋„ ์—†์Œ
  • keyword-registry.ts๋Š” AGENTS.md ์ฃผ์ž…์šฉ์ด ์•„๋‹ˆ๋ผ, keyword-detector.ts(ํ”„๋กœ๊ทธ๋ž˜๋ฐ์  2์ฐจ ๊ฐ์ง€)์— ํ‚ค์›Œ๋“œ ์ •์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ (์†Œ์Šค ํ™•์ธ: setup.ts์—์„œ importํ•˜์ง€ ์•Š์Œ)
  • ๋Œ€์†Œ๋ฌธ์ž ๋ฌด์‹œ, ๋ฉ”์‹œ์ง€ ์–ด๋””์—์„œ๋“  ๋งค์นญ
  • ํ™•๋ฅ ๋ก ์ : ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ์–ด๋„ LLM์ด ๋ฌด์‹œํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅด๊ฒŒ ํ•ด์„ํ•  ์ˆ˜ ์žˆ์Œ (์˜จ๋„ยท์ปจํ…์ŠคํŠธ ํฌํ™”ยทํ‘œํ˜„ ๋ณ€ํ˜• ๋“ฑ)

keyword-detector.ts / keyword-registry.ts โ€” ์‹คํ–‰ ์‹œ์ ๊ณผ ์—ญํ•  (์†Œ์Šค ํ™•์ธ)

์†Œ์Šค ์ฃผ์„ (src/hooks/keyword-detector.ts:1-12):

โ€œIn OMC, this runs as a UserPromptSubmit hook that detects magic keywords and injects skill prompts via system-reminder.โ€ โ€œIn OMX, this logic is embedded in the AGENTS.md orchestration brain, and can also be used by the notify hook for state tracking.โ€ โ€œWhen Codex CLI adds pre-hook support, this module can be promoted to an external hook handler.โ€

keyword-registry.ts โ€” ํ‚ค์›Œ๋“œ ์ •์˜ ๋ฐ์ดํ„ฐ ๋ชจ๋“ˆ

  • ๋…๋ฆฝ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. keyword-detector.ts๊ฐ€ importํ•˜๋Š” ๋ฐ์ดํ„ฐ ๋ชจ๋“ˆ์ผ ๋ฟ
  • 58๊ฐœ ํ‚ค์›Œ๋“œ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ { keyword, skill, priority, guidance } ํ˜•ํƒœ๋กœ export
  • AGENTS.md์— ์ฃผ์ž…ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Œ (setup.ts์—์„œ importํ•˜์ง€ ์•Š์Œ โ€” ์†Œ์Šค ํ™•์ธ ์™„๋ฃŒ)

keyword-detector.ts โ€” ์‹คํ–‰ ์‹œ์ 

OMX์˜ ์ž์ฒด Hook ์‹œ์Šคํ…œ(src/hooks/extensibility/)์ด ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ•  ๋•Œ Control Plane์—์„œ ํ˜ธ์ถœ๋œ๋‹ค.

  • recordSkillActivation(): ์‚ฌ์šฉ์ž ์ž…๋ ฅ ํ…์ŠคํŠธ์—์„œ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  skill-active-state.json์— ์ƒํƒœ ๊ธฐ๋ก
  • ์ด ์ƒํƒœ ํŒŒ์ผ์€ agents-overlay.ts๊ฐ€ ๋‹ค์Œ ์„ธ์…˜์˜ ์˜ค๋ฒ„๋ ˆ์ด ์ƒ์„ฑ ์‹œ ์ฐธ์กฐ
  • Codex CLI์—๋Š” UserPromptSubmit ๊ฐ™์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ€๋กœ์ฑ„๊ธฐ ์ด๋ฒคํŠธ๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ์ง€ํ•ด๋„ LLM์— ๊ฒฐ๊ณผ๋ฅผ ๊ฐ•์ œ ์ฃผ์ž…ํ•  ์ฑ„๋„์ด ์—†์Œ
graph LR
    KR["keyword-registry.ts<br>(๋ฐ์ดํ„ฐ ๋ชจ๋“ˆ)"] -->|import| KD["keyword-detector.ts<br>(ํ”„๋กœ๊ทธ๋ž˜๋ฐ์  ๊ฐ์ง€)"]
    KD -->|recordSkillActivation()| SF["skill-active-state.json"]
    SF -->|๋‹ค์Œ ์„ธ์…˜์—์„œ ์ฝ๊ธฐ| AO["agents-overlay.ts"]

    AM["AGENTS.md<br>&lt;keyword_detection&gt; ์„น์…˜"] -->|LLM์ด ์ง์ ‘ ํ•ด์„| CX["Codex CLI (LLM)"]

    style AM fill:#fef7e0
    style KD fill:#e8f0fe

๊ฒฐ๋ก : AGENTS.md๊ฐ€ 1์ฐจ ๊ฐ์ง€(ํ™•๋ฅ ๋ก ์ , LLM ํ•ด์„), keyword-detector.ts๋Š” ์ƒํƒœ ์ถ”์ ์šฉ 2์ฐจ ๋ณด์กฐ. OMX์˜ ๋ชจ๋“  ์Šคํ‚ฌ ์‹คํ–‰์€ ๊ฒฐ๊ตญ LLM์˜ ํŒ๋‹จ์— ์˜์กด โ†’ ์ „ ๊ณ„์ธต์ด ํ™•๋ฅ ๋ก ์ .

Hook ํ™•์žฅ์„ฑ โ€” .omx/hooks/*.mjs (์†Œ์Šค ํ™•์ธ: src/hooks/extensibility/)

Codex CLI ์ž์ฒด์—๋Š” Hook ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ์ด ์—†๋‹ค. ํ•˜์ง€๋งŒ OMX๋Š” ์ž์ฒด Hook ์‹œ์Šคํ…œ์„ ๋ฐ‘๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•˜์—ฌ .omx/hooks/*.mjs ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ง€์›ํ•œ๋‹ค.

์ž‘๋™ ์›๋ฆฌ โ€” Codex CLI์— Hook์ด ์—†๋Š”๋ฐ ์–ด๋–ป๊ฒŒ?

OMX๋Š” ๋‘ ๊ฐ€์ง€ ๊ฒฝ๋กœ๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ•œ๋‹ค:

  • native ์ด๋ฒคํŠธ: OMX์˜ Control Plane(src/cli/index.ts)์ด Codex CLI ํ”„๋กœ์„ธ์Šค์˜ ์ƒ๋ช…์ฃผ๊ธฐ ์ง€์ ์—์„œ ์ฝ”๋“œ ๋ ˆ๋ฒจ๋กœ ์ง์ ‘ ๋ฐœํ–‰ (emitNativeHookEvent() ํ˜ธ์ถœ). ํ„ฐ๋ฏธ๋„ ์ถœ๋ ฅ์„ ํŒŒ์‹ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹˜.
  • derived ์ด๋ฒคํŠธ: ๋ณ„๋„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ”„๋กœ์„ธ์Šค(scripts/hook-derived-watcher.js)๊ฐ€ Codex CLI์˜ rollout JSONL ํŒŒ์ผ(~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl)์„ ํด๋ง(800ms ์ฃผ๊ธฐ)ํ•˜์—ฌ ํŒŒ์‹ฑยท์ถ”๋ก . confidence ์ ์ˆ˜ ํฌํ•จ (0~1 ๋ฒ”์œ„). OMX_HOOK_DERIVED_SIGNALS=1 ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ํ™œ์„ฑํ™”.
graph LR
    subgraph Native ["Native ๊ฒฝ๋กœ (์ฝ”๋“œ ๋ ˆ๋ฒจ ์ง์ ‘ ๋ฐœํ–‰)"]
        CLI["src/cli/index.ts"] -->|"emitNativeHookEvent()"| D["dispatcher.ts"]
    end

    subgraph Derived ["Derived ๊ฒฝ๋กœ (rollout ํŒŒ์ผ ํด๋ง)"]
        CX["Codex CLI"] -->|"rollout-*.jsonl ๊ธฐ๋ก"| RF["~/.codex/sessions/.../rollout-*.jsonl"]
        RF -->|"800ms ํด๋ง"| W["hook-derived-watcher.js"]
        W -->|"ํŒŒ์‹ฑ + ์ถ”๋ก  (confidence)"| D
    end

    D -->|"child process spawn"| P1[".omx/hooks/plugin-a.mjs"]
    D -->|"child process spawn"| P2[".omx/hooks/plugin-b.mjs"]

    style CLI fill:#e8f0fe
    style W fill:#fef7e0

์ด๋ฒคํŠธ ๋ชจ๋ธ (์†Œ์Šค: src/hooks/extensibility/types.ts, src/cli/index.ts, scripts/hook-derived-watcher.js)

types.ts์—๋Š” 16๊ฐœ ์ด๋ฒคํŠธ + open-ended ํ™•์žฅ(string & {})์ด ์ •์˜๋˜์–ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ types.ts์˜ source ๋ถ„๋ฅ˜์™€ ์‹ค์ œ ๋ฐœํ–‰ ๋ฐฉ์‹์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ, ์†Œ์Šค ์ฝ”๋“œ ๊ธฐ์ค€์œผ๋กœ 3๊ฐœ ๊ทธ๋ฃน์œผ๋กœ ๋ถ„๋ฅ˜ํ•œ๋‹ค.

Native ์ด๋ฒคํŠธ โ€” ์‹ค์ œ ๋ฐœํ–‰ ํ™•์ธ (์†Œ์Šค: src/cli/index.ts:1764)

emitNativeHookEvent() ํ•จ์ˆ˜๊ฐ€ ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ ๊ฒฐ์ •๋ก ์ ์œผ๋กœ ์ง์ ‘ ๋ฐœํ–‰ํ•œ๋‹ค. ํƒ€์ž… ์‹œ๊ทธ๋‹ˆ์ฒ˜์— 4๊ฐœ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์œผ๋‚˜, ํ˜„์žฌ ์‹ค์ œ ๋ฐœํ–‰ ์ฝ”๋“œ๊ฐ€ ํ™•์ธ๋œ ๊ฒƒ์€ 2๊ฐœ์ด๋‹ค.

์ด๋ฒคํŠธ๊ฐ์ง€ ๋ฐฉ์‹๋ฐœํ–‰ ์œ„์น˜๋น„๊ณ 
session-startCodex CLI ํ”„๋กœ์„ธ์Šค spawn ์งํ›„ ์ง์ ‘ ๋ฐœํ–‰index.ts:1323context์— project ์ •๋ณด ํฌํ•จ
session-endCodex CLI ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ์‹œ cleanup์—์„œ ์ง์ ‘ ๋ฐœํ–‰index.ts:1746exit code๋กœ finished/failed status ๊ฒฐ์ • ํ›„ context์— ํฌํ•จ
session-idleํƒ€์ž… ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ์ •์˜๋จindex.ts:1766 (์‹œ๊ทธ๋‹ˆ์ฒ˜)๋ฐœํ–‰ ์ฝ”๋“œ ๋ฏธํ™•์ธ
turn-completeํƒ€์ž… ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ์ •์˜๋จindex.ts:1766 (์‹œ๊ทธ๋‹ˆ์ฒ˜)ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ๋งŒ ์‚ฌ์šฉ, ๋ฐœํ–‰ ์ฝ”๋“œ ๋ฏธํ™•์ธ
// src/cli/index.ts โ€” Native ์ด๋ฒคํŠธ ๋ฐœํ–‰ ํ•จ์ˆ˜ (ํƒ€์ž… ์‹œ๊ทธ๋‹ˆ์ฒ˜์— 4๊ฐœ ์ •์˜)
async function emitNativeHookEvent(
  cwd: string,
  event: 'session-start' | 'session-end' | 'session-idle' | 'turn-complete',
  opts: { session_id?: string; context?: Record<string, unknown>; ... } = {},
): Promise<void> {
  const payload = buildHookEvent(event, { source: 'native', context: opts.context || {} });
  await dispatchHookEvent(payload, { cwd });
}
 
// session-start ๋ฐœํ–‰ (index.ts:1323) โ€” Codex CLI spawn ์งํ›„
await emitNativeHookEvent(cwd, 'session-start', {
  session_id: sessionId,
  context: { project_path: cwd, project_name: basename(cwd), ... },
});
 
// session-end ๋ฐœํ–‰ (index.ts:1746) โ€” Codex CLI ์ข…๋ฃŒ ์‹œ cleanup
const normalizedEvent = process.exitCode && process.exitCode !== 0 ? 'failed' : 'finished';
await emitNativeHookEvent(cwd, 'session-end', {
  session_id: sessionId,
  context: { status: normalizedEvent, exit_code: process.exitCode, ... },
  // โ†‘ finished/failed๋Š” ๋ณ„๋„ ์ด๋ฒคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ session-end์˜ context.status๋กœ ํฌํ•จ
});

์ฐธ๊ณ : finished์™€ failed๋Š” ๋ณ„๋„ ์ด๋ฒคํŠธ๋กœ ๋ฐœํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. session-end ์ด๋ฒคํŠธ์˜ context ๋‚ด status ํ•„๋“œ('finished' ๋˜๋Š” 'failed')๋กœ ํฌํ•จ๋œ๋‹ค.

Derived ์ด๋ฒคํŠธ โ€” ์‹ค์ œ ๋ฐœํ–‰ ํ™•์ธ (์†Œ์Šค: scripts/hook-derived-watcher.js)

hook-derived-watcher.js๊ฐ€ Codex CLI์˜ rollout JSONL ํŒŒ์ผ์„ ํด๋งยทํŒŒ์‹ฑํ•˜์—ฌ ํ™•๋ฅ ๋ก ์ ์œผ๋กœ ์ถ”๋ก  ๋ฐœํ–‰ํ•œ๋‹ค. ๋ชจ๋“  derived ์ด๋ฒคํŠธ๋Š” confidence ์ ์ˆ˜๋ฅผ ํฌํ•จํ•œ๋‹ค.

์ด๋ฒคํŠธ๊ฐ์ง€ ๋ฐฉ์‹confidence๋น„๊ณ 
pre-tool-userollout JSONL์—์„œ tool_call_start ๋“ฑ payload type ๋งค์นญ0.80types.ts: derived
post-tool-userollout JSONL์—์„œ tool_call_end ๋“ฑ payload type ๋งค์นญ0.80types.ts: derived
needs-inputassistant_message์—์„œ ์งˆ๋ฌธ ํŒจํ„ด ์ •๊ทœ์‹ ๋งค์นญ (?, can you, please provide ๋“ฑ)0.55types.ts: derived. ๊ฐ€์žฅ ๋‚ฎ์€ confidence
test-startedexec_command๊ฐ€ ํ…Œ์ŠคํŠธ ๋ช…๋ น์–ด๋กœ ๋ถ„๋ฅ˜(classifyExecCommand)๋  ๋•Œ0.92types.ts์—์„œ๋Š” native๋กœ ์ •์˜๋˜๋‚˜ ์‹ค์ œ๋กœ๋Š” derived ๋ฐœํ–‰
test-finishedํ…Œ์ŠคํŠธ ๋ช…๋ น์–ด ๊ฒฐ๊ณผ ์„ฑ๊ณต ์‹œ (result.success === true)0.95types.ts์—์„œ๋Š” native๋กœ ์ •์˜๋˜๋‚˜ ์‹ค์ œ๋กœ๋Š” derived ๋ฐœํ–‰
test-failedํ…Œ์ŠคํŠธ ๋ช…๋ น์–ด ๊ฒฐ๊ณผ ์‹คํŒจ ์‹œ (result.success === false)0.95types.ts์—์„œ๋Š” native๋กœ ์ •์˜๋˜๋‚˜ ์‹ค์ œ๋กœ๋Š” derived ๋ฐœํ–‰
pr-createdPR ์ƒ์„ฑ ๋ช…๋ น์–ด ๊ฒฐ๊ณผ์—์„œ PR ๋ฒˆํ˜ธ/URL ๊ฐ์ง€0.97types.ts์—์„œ๋Š” native๋กœ ์ •์˜๋˜๋‚˜ ์‹ค์ œ๋กœ๋Š” derived ๋ฐœํ–‰
// scripts/hook-derived-watcher.js โ€” Derived ์ด๋ฒคํŠธ์˜ ํ•ต์‹ฌ ๊ฐ์ง€ ๋กœ์ง
 
// 1. rollout JSONL ํŒŒ์ผ ํด๋ง (800ms ์ฃผ๊ธฐ)
const pollMs = 800;
async function pollFiles() {
  for (const [path, meta] of fileState.entries()) {
    const delta = content.slice(meta.offset);  // ๋งˆ์ง€๋ง‰ ์ฝ์€ ์œ„์น˜๋ถ€ํ„ฐ ์ƒˆ ๋‚ด์šฉ๋งŒ
    for (const line of lines) { await processLine(meta, line); }
  }
}
 
// 2. pre-tool-use / post-tool-use ๊ฐ์ง€ โ€” payload type ๋งค์นญ
function inferDerivedEvent(parsed, meta) {
  if (['tool_call_start', 'tool_use_start'].includes(payloadType)) {
    return { event: 'pre-tool-use', confidence: 0.8, source: 'derived' };
  }
  if (['tool_call_end', 'tool_use_end'].includes(payloadType)) {
    return { event: 'post-tool-use', confidence: 0.8, source: 'derived' };
  }
  // 3. needs-input ๊ฐ์ง€ โ€” ์งˆ๋ฌธ ํŒจํ„ด ์ •๊ทœ์‹ (๊ฐ€์žฅ ๋‚ฎ์€ confidence)
  if (payloadType === 'assistant_message') {
    const looksLikeQuestion = /\?|\b(can you|could you|please provide|need input)\b/i.test(message);
    if (looksLikeQuestion) return { event: 'needs-input', confidence: 0.55, source: 'derived' };
  }
}
 
// 4. test-started/finished/failed, pr-created ๊ฐ์ง€ โ€” exec_command ๊ฒฐ๊ณผ ๋ถ„์„
function inferOperationalCall(parsed, meta) {
  if (payload.name === 'exec_command') {
    const classified = classifyExecCommand(command);  // 'test' | 'pr-create' | ...
    // test ๋ช…๋ น์–ด ์‹œ์ž‘ โ†’ test-started (confidence 0.92)
    // test ๊ฒฐ๊ณผ ์„ฑ๊ณต  โ†’ test-finished (confidence 0.95)
    // test ๊ฒฐ๊ณผ ์‹คํŒจ  โ†’ test-failed (confidence 0.95)
    // PR ์ƒ์„ฑ ๊ฒฐ๊ณผ    โ†’ pr-created (confidence 0.97)
  }
}

types.ts ๋ถ„๋ฅ˜ vs ์‹ค์ œ ๋ถ„๋ฅ˜ ๋ถˆ์ผ์น˜: test-started, test-finished, test-failed, pr-created๋Š” types.ts์—์„œ native๋กœ ์ •์˜๋˜์–ด ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” hook-derived-watcher.js์—์„œ buildDerivedHookEvent()๋กœ ๋ฐœํ–‰ํ•œ๋‹ค. ์ด๋“ค์€ rollout ํŒŒ์ผ์˜ exec_command ์ถœ๋ ฅ์„ ๋ถ„์„ํ•˜์—ฌ ์ถ”๋ก ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ์กฐ์ ์œผ๋กœ derived์— ํ•ด๋‹นํ•œ๋‹ค.

ํƒ€์ž… ์ •์˜๋งŒ ์กด์žฌ โ€” ๋ฐœํ–‰ ๋ฏธํ™•์ธ

์ด๋ฒคํŠธtypes.ts ๋ถ„๋ฅ˜๋น„๊ณ 
blockednative๋ฐœํ–‰ ์ฝ”๋“œ ๋ฏธํ™•์ธ. ์—๋Ÿฌ ํ•ธ๋“ค๋ง์—์„œ ๋ฌธ์ž์—ด๋กœ๋งŒ ์‚ฌ์šฉ
finishednative๋ณ„๋„ ์ด๋ฒคํŠธ ์•„๋‹˜. session-end์˜ context status๋กœ ํฌํ•จ
failednative๋ณ„๋„ ์ด๋ฒคํŠธ ์•„๋‹˜. session-end์˜ context status๋กœ ํฌํ•จ
retry-needednative๋ฐœํ–‰ ์ฝ”๋“œ ๋ฏธํ™•์ธ
handoff-needednative๋ฐœํ–‰ ์ฝ”๋“œ ๋ฏธํ™•์ธ

ํ”Œ๋Ÿฌ๊ทธ์ธ SDK (HookPluginSdk)

ํ”Œ๋Ÿฌ๊ทธ์ธ์€ onHookEvent(event, sdk) ํ•จ์ˆ˜๋ฅผ exportํ•˜๋ฉฐ, SDK๋กœ ๋‹ค์Œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

SDK ๋ฉ”์„œ๋“œ๊ธฐ๋Šฅ
sdk.tmux.sendKeys()tmux pane์— ํ‚ค ์ž…๋ ฅ ์ „์†ก
sdk.log.info/warn/error().omx/logs/์— ๋กœ๊ทธ ๊ธฐ๋ก
sdk.state.read/write/delete/all().omx/state/์— ์ƒํƒœ ์ฝ๊ธฐ/์“ฐ๊ธฐ

ํ™œ์„ฑํ™” ๋ฐ ๋น„๊ต

  • OMX_HOOK_PLUGINS=1 ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ํ™œ์„ฑํ™” (๊ธฐ๋ณธ ๋น„ํ™œ์„ฑํ™”)
  • .omx/hooks/ ๋””๋ ‰ํ† ๋ฆฌ์— .mjs ํŒŒ์ผ๋กœ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ž‘์„ฑ
  • ํ”Œ๋Ÿฌ๊ทธ์ธ์€ child process๋กœ ๊ฒฉ๋ฆฌ ์‹คํ–‰ (timeout ์ง€์›)
๋น„๊ตOMC HookOMX Hook
๊ธฐ๋ฐ˜Claude Code์˜ ๋นŒํŠธ์ธ Hook ์‹œ์Šคํ…œOMX๊ฐ€ ์ž์ฒด ๊ตฌํ˜„ํ•œ Hook ์‹œ์Šคํ…œ
์ด๋ฒคํŠธ ์ˆ˜21๊ฐœ16๊ฐœ ์ •์˜ (์‹ค์ œ ๋ฐœํ–‰: native 2๊ฐœ + derived 7๊ฐœ)
Native ๊ฐ์ง€Claude Code๊ฐ€ ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ๋ฐœํ–‰OMX ์ฝ”๋“œ๊ฐ€ ์ƒ๋ช…์ฃผ๊ธฐ ์ง€์ ์—์„œ ์ง์ ‘ ๋ฐœํ–‰ (emitNativeHookEvent())
Derived ๊ฐ์ง€์—†์Œ (๋ชจ๋‘ ํ™•์ •์ )hook-derived-watcher.js๊ฐ€ rollout JSONL ํŒŒ์ผ ํด๋งยทํŒŒ์‹ฑ์œผ๋กœ ์ถ”๋ก  (confidence ํฌํ•จ)
ํ™œ์„ฑํ™”hooks.json์— ๋“ฑ๋กํ•˜๋ฉด ์ž๋™ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ opt-in (OMX_HOOK_PLUGINS=1, derived๋Š” OMX_HOOK_DERIVED_SIGNALS=1)
ํ”„๋กœํ† ์ฝœstdin/stdout JSONchild process spawn + SDK ์ฃผ์ž…
์—ญํ• ํ‚ค์›Œ๋“œ ๊ฐ์ง€์˜ ์ฃผ์š” ๋ฉ”์ปค๋‹ˆ์ฆ˜ (๊ฒฐ์ •๋ก ์ )์ƒํƒœ ์ถ”์ ยท๋ชจ๋‹ˆํ„ฐ๋ง ๋ณด์กฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜
ํ•ต์‹ฌ ๊ฐ์ง€Hook ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹ด๋‹นAGENTS.md๊ฐ€ ๋‹ด๋‹น
์‹คํ–‰ ๋ณด์žฅ๊ฒฐ์ •๋ก ์  โ€” LLM ์™ธ๋ถ€์—์„œ ๊ฐ•์ œ ์ฃผ์ž…ํ™•๋ฅ ๋ก ์  โ€” LLM์ด ํŒ๋‹จํ•˜์—ฌ ์‹คํ–‰

์ฐธ๊ณ  ๋ฌธ์„œ