Disclaimer:
kmsg๋ Kakao Corp. ์ ๊ณต์ ๋๊ตฌ๊ฐ ์๋๋๋ค. ์ฌ์ฉ์๋ ๋ณธ์ธ ๊ณ์ /ํ๊ฒฝ์์ ๊ด๋ จ ๋ฒ๊ท, ์๋น์ค ์ฝ๊ด, ํ์ฌ ๋ณด์ ์ ์ฑ ์ ์ค์ํ ์ฑ ์์ด ์์ต๋๋ค. ์ด ๋๊ตฌ ์ฌ์ฉ์ผ๋ก ๋ฐ์ํ ์ ์๋ ๊ณ์ ์ ํ, ์ค์๋, ๋ฐ์ดํฐ ์์ค, ๊ธฐํ ์ํด์ ๋ํ ์ฑ ์์ ์ฌ์ฉ์์๊ฒ ์์ต๋๋ค. LOCO Protocol ์ด ์๋ AX ๋ฅผ ์ฌ์ฉํ ์ด์ ์ ๊ณ์ ์ ์ฌ ๊ฐ๋ฅ์ฑ์ ๋ํ ์ ๊ฐ์ธ์ ์ธ ํ๋จ์ ์ KakaoTalk ์ LOCO Protocol ์ ์ฌ์ฉํ์ง ์๋์? ํญ๋ชฉ์ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
kmsg ๋ macOS์์ ์นด์นด์คํก ๋ฉ์์ง๋ฅผ CLI ๋ก ์ฝ๊ณ ๋ณด๋ด๋ ๋๊ตฌ์
๋๋ค. ๋จ์ํ ์๋ CLI ๋ฅผ ๋์ด, AI Agent ๋๋ Hook ์ด๋ฒคํธ ๋ฑ์ ์๋ํ ํ์ดํ๋ผ์ธ์ ์ฐ๊ฒฐํ๊ธฐ ์ฝ๋๋ก ๊ตฌํํ์ต๋๋ค. kmsg ๋ openclaw ์ ์ฐฝ์์์ธ steipete ๊ฐ ๋ง๋ iMessage ์ปจํธ๋กค์ ์ํ CLI ๋๊ตฌ์ธ imsg ์ ์๊ฐ์ ๋ฐ์ ์์ฑ๋์์ต๋๋ค.
record.mp4
์๊ตฌ์ฌํญ:
- macOS 13+
- macOS์ฉ KakaoTalk ์ค์น
brew install channprj/tap/kmsgํน์ ๋ฆด๋ฆฌ์ฆ๋ฅผ ๊ณ ์ ํด์ ์ค์นํ๋ ค๋ฉด exact version formula๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. tap์๋ ์ต์ 10๊ฐ ๋ฆด๋ฆฌ์ฆ๋ง ์ ์ง๋ฉ๋๋ค.
brew install channprj/tap/kmsg@2026.0422.22mkdir -p ~/.local/bin && curl -fL https://github.com/channprj/kmsg/releases/latest/download/kmsg-macos-universal -o ~/.local/bin/kmsg && chmod +x ~/.local/bin/kmsg์ค์น ํ์ธ์ ์๋์ ๊ฐ์ด ์งํํฉ๋๋ค.
kmsg status๊ถํ ํ์ ์ด ๋จ๋ฉด ํ์ฉํด ์ฃผ์ธ์.
kmsg status
kmsg auth login
kmsg auth login --auto
kmsg -v
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "์๋
ํ์ธ์"
kmsg send --chat-id "chat_7f42c5e1d9ab" "์๋
ํ์ธ์"
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "$(date '+%Y-%m-%d %H:%M:%S') ํ
์คํธ"
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ" --keep-window
kmsg send-image "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "/path/to/image.png"
kmsg mcp-server
kmsg chats
kmsg chats --json
kmsg read "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --limit 20
kmsg read "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --limit 20 --keep-window
kmsg read "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --limit 20 --json
kmsg read "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --limit 20 --deep-recovery
kmsg watch "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ"
kmsg watch "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --json
kmsg watch "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --json --poll-interval 0.5
kmsg inspect --window 0 --depth 20 --debug-layout์ต์
์ ๋น๋ ๊ธฐ์ค kmsg --help, kmsg <command> --help ์ถ๋ ฅ๊ณผ ๋์ผํ๊ฒ ๊ด๋ฆฌ๋ฉ๋๋ค.
kmsg status [--verbose]--verbose: ์์ธ ์ํ ์ถ๋ ฅ
status, chats, read, send, send-image, watch, cache warmup์ ์นด์นด์คํก ๋ก๊ทธ์ธ์ด ํ๋ ค ์์ผ๋ฉด ์ ์ฅ๋ ์๊ฒฉ ์ฆ๋ช
์ผ๋ก ์๋ ๋ก๊ทธ์ธ์ ์๋ํฉ๋๋ค. ์ ์ฅ๋ ์ ๋ณด๊ฐ ์๊ฑฐ๋ ๋ถ์์ ํ๋ฉด ํฐ๋ฏธ๋์์ ์์ด๋/๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅ๋ฐ์ ~/.config/kmsg/credentials.json์ ์ ์ฅํ๊ณ , ๋น๋ฐ๋ฒํธ ์ํธํค๋ ~/.config/kmsg/credentials/์ ๋ณ๋๋ก ๋ณด๊ดํฉ๋๋ค.
kmsg auth login [--auto] [--trace-ax]--auto: ์ ์ฅ๋ ์๊ฒฉ ์ฆ๋ช ์ด ์์ผ๋ฉด ๊ทธ๋๋ก ์ฌ์ฉํ๊ณ , ์์ผ๋ฉด ์ ๋ ฅ๋ฐ์ ์ ์ฅ ํ ๋ก๊ทธ์ธ--trace-ax: AX ํ์/์ฌ์๋ ๋ก๊ทธ ์ถ๋ ฅ
๊ธฐ๋ณธ kmsg auth login์ ์์ด๋/๋น๋ฐ๋ฒํธ๋ฅผ ์๋ก ์
๋ ฅ๋ฐ์ ์ ์ฅํ๊ณ ๋ก๊ทธ์ธํฉ๋๋ค. ๋น๋ฐ๋ฒํธ๋ ํ๋ฌธ์ด ์๋๋ผ ์ํธํ๋ ํํ๋ก ์ ์ฅ๋ฉ๋๋ค.
kmsg chats [--verbose] [--limit <limit>] [--trace-ax] [--json] [--keep-window]-v, --verbose: ์์ธ ์ ๋ณด ์ถ๋ ฅ-l, --limit <limit>: ์ต๋ ์ฑํ ๋ชฉ๋ก ๊ฐ์ (๊ธฐ๋ณธ๊ฐ: 20)--trace-ax: AX ํ์/์ฌ์๋ ๋ก๊ทธ ์ถ๋ ฅ--json:chat_id๋ฅผ ํฌํจํ ๊ตฌ์กฐํ JSON ์ถ๋ ฅ-k, --keep-window:chats์คํ ์ค ์๋์ผ๋ก ์ฐ ์ฐฝ์ ์ ์ง
๊ธฐ๋ณธ ์ถ๋ ฅ์๋ ๊ฐ ์ฑํ
์ chat_id๊ฐ ํจ๊ป ํ์๋ฉ๋๋ค. chat_id๋ ๋ก์ปฌ registry(~/.kmsg/chat-registry.json)์ ์ ์ฅ๋๋ synthetic ID์ด๋ฉฐ, ์ฑํ
๋ฐฉ ์ด๋ฆ์ ๊ธฐ์ค์ผ๋ก ์์ฑ/์ฌ์ฌ์ฉ๋ฉ๋๋ค. ๊ฐ์ ์ด๋ฆ์ ๋ฐฉ์ด ์ฌ๋ฌ ๊ฐ๋ฉด registry๊ฐ ๋ณ๋ ID๋ฅผ ์ ์งํ๊ณ , ๋ฐฉ ์ด๋ฆ์ด ๋ฐ๋๋ฉด ์ ID๋ก ์ทจ๊ธํฉ๋๋ค. chats๊ฐ ์คํ ์ค ์ฐฝ์ ์๋์ผ๋ก ์ด์๋ค๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ์ข
๋ฃ ์ ๋ซ๊ณ , --keep-window์ผ ๋๋ง ์ ์งํฉ๋๋ค.
kmsg read <chat> [--limit <limit>] [--debug] [--trace-ax] [--keep-window] [--deep-recovery] [--json]-l, --limit <limit>: ์ต๋ ๋ฉ์์ง ๊ฐ์ (๊ธฐ๋ณธ๊ฐ: 20)--debug: raw element ๋๋ฒ๊ทธ ์ ๋ณด ์ถ๋ ฅ--trace-ax: AX ํ์/์ฌ์๋ ๋ก๊ทธ ์ถ๋ ฅ-k, --keep-window: ์๋์ผ๋ก ์ฐ ์ฑํ ์ฐฝ๊ณผ ๋ฆฌ์คํธ์ฐฝ ์ ์ง--deep-recovery: ๋น ๋ฅธ ํ์ ์คํจ ์ deep recovery ์ํ--json: JSON ํ์์ผ๋ก ์ถ๋ ฅ
kmsg watch <chat> [--poll-interval <seconds>] [--trace-ax] [--keep-window] [--deep-recovery] [--json] [--include-system]--poll-interval <seconds>: ํด๋ง ์ฃผ๊ธฐ (๊ธฐ๋ณธ๊ฐ:0.2, ๋ฒ์:0.2...10.0)--trace-ax: AX ํ์/์ฌ์๋ ๋ก๊ทธ ์ถ๋ ฅ-k, --keep-window: ์๋์ผ๋ก ์ฐ ์ฑํ ์ฐฝ ์ ์ง--deep-recovery: ๋น ๋ฅธ ํ์ ์คํจ ์ deep recovery ์ํ--json: ์ ๋ฉ์์ง ์ด๋ฒคํธ๋ฅผ pretty JSON ๊ฐ์ฒด๋ก ๊ณ์ ์ถ๋ ฅ--include-system: ๋ ์ง ๊ตฌ๋ถ์ ๋ฑ ์์คํ ์ฑ ๋ฉ์์ง๋ ํฌํจ
watch๋ ์์ ์ ํ์ฌ ๋ํ๋ฅผ baseline์ผ๋ก๋ง ์ก๊ณ ์ถ๋ ฅํ์ง ์์ผ๋ฉฐ, transcript๊ฐ ๋ฆ๊ฒ ๋ก๋ฉ๋๋ ๊ฒฝ์ฐ๋ฅผ ํผํ๊ธฐ ์ํด ์ต๋ 1-2์ด ์ ๋ silent warm-up์ผ๋ก baseline์ ์์ ํํ ๋ค ๊ฐ์๋ฅผ ์์ํฉ๋๋ค. ๋ํ ํ์ฑ๋ ๋ ์ง/์๊ฐ์ ๊ธฐ์ค์ผ๋ก watch ์์ ์์ ์ด์ ๋ฉ์์ง๋ ์ถ๋ ฅํ์ง ์์ต๋๋ค. ์์ ํ ์๊ฐ์ ์ถ์ ํ ์ ์๋ ํ์ ๋ณด์์ ์ผ๋ก ์จ๊ธธ ์ ์์ต๋๋ค. steady-state์์๋ ๋ง์ง๋ง์ผ๋ก ์ฑ๊ณตํ transcript context๋ฅผ ์ฐ์ ์ฌ์ฌ์ฉํ๊ณ , transcript root๋ AX cache happy path๋ฅผ ์ฌ์ฉํด 200ms polling์ ๊ฒฌ๋ ์ ์๊ฒ ํ์ต๋๋ค. ๊ธฐ๋ณธ ๋ชจ๋๋ ์ผ๋ฐ ๋ํ ๋ฉ์์ง๋ง ์ถ๋ ฅํ๊ณ , --include-system์ผ ๋๋ง ์์คํ
์ฑ ๋ฉ์์ง๋ฅผ ํฌํจํฉ๋๋ค. --json์์๋ ์ด๋ฒคํธ๋ง๋ค ๋ณ๋ JSON ๊ฐ์ฒด๊ฐ stdout์ผ๋ก ์ถ๋ ฅ๋๊ณ , --trace-ax๋ ๊ณ์ stderr์๋ง ๊ธฐ๋ก๋ฉ๋๋ค.
kmsg send <recipient> <message> [--dry-run] [--trace-ax] [--no-cache] [--refresh-cache] [--keep-window] [--deep-recovery]
kmsg send --chat-id <chat-id> <message> [--dry-run] [--trace-ax] [--no-cache] [--refresh-cache] [--keep-window] [--deep-recovery]--chat-id <chat-id>:kmsg chats์์ ์ถ๋ ฅ๋chat_id๋ก ์ ์ก--dry-run: ์ค์ ์ ์ก ์์ด ์๋ฎฌ๋ ์ด์ --trace-ax: AX ํ์/์ฌ์๋ ๋ก๊ทธ ์ถ๋ ฅ--no-cache: ์ด๋ฒ ์คํ์์ AX path cache ๋นํ์ฑํ--refresh-cache: ์ด๋ฒ ์คํ์์ AX path cache ๊ฐ์ ์ฌ๊ตฌ์ฑ-k, --keep-window: ์๋์ผ๋ก ์ฐ ์ฑํ ์ฐฝ๊ณผ ๋ฆฌ์คํธ์ฐฝ ์ ์ง--deep-recovery: ๋น ๋ฅธ ํ์ ์คํจ ์ deep recovery ์ํ
--chat-id ์ ์ก์ local registry์์ ์ฑํ
๋ฐฉ ์ด๋ฆ์ ์ญ์กฐํํ ๋ค ๊ธฐ์กด search/open ๊ฒฝ๋ก๋ก ์ฑํ
์ ์ฝ๋๋ค. registry์ ์๋ ID๋ ์ฆ์ ์คํจํฉ๋๋ค. send๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ก ํ ์ฑํ
์ฐฝ๊ณผ ์นดํก ๋ฆฌ์คํธ์ฐฝ์ ์ ๋ฆฌํ๊ณ , --keep-window์ผ ๋๋ง ๋ ๋ค ์ ์งํฉ๋๋ค.
kmsg send-image <recipient> <image-path> [--trace-ax] [--no-cache] [--keep-window] [--deep-recovery]--trace-ax: AX ํ์/์ฌ์๋ ๋ก๊ทธ ์ถ๋ ฅ--no-cache: ์ด๋ฒ ์คํ์์ AX path cache ๋นํ์ฑํ-k, --keep-window: ์๋์ผ๋ก ์ฐ ์ฑํ ์ฐฝ๊ณผ ๋ฆฌ์คํธ์ฐฝ ์ ์ง--deep-recovery: ๋น ๋ฅธ ํ์ ์คํจ ์ deep recovery ์ํ
send-image๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ก ํ ์ฑํ
์ฐฝ๊ณผ ์นดํก ๋ฆฌ์คํธ์ฐฝ์ ์ ๋ฆฌํ๊ณ , --keep-window์ผ ๋๋ง ๋ ๋ค ์ ์งํฉ๋๋ค. ํ์ธ ์ํธ๊ฐ ๋งค์ฐ ๋น ๋ฅด๊ฒ ์ฌ๋ผ์ง๊ฑฐ๋ ์๋ต๋๋ ๊ฒฝ์ฐ๋ ์ฑ๊ณต์ผ๋ก ์ฒ๋ฆฌํ๋๋ก ๋์ด ์์ต๋๋ค.
kmsg inspect [--depth <depth>] [--window <window>] [--show-attributes] [--show-path] [--show-frame] [--show-index] [--show-flags] [--show-actions] [--debug-layout] [--row-summary] [--row-range <start:end>]-d, --depth <depth>: ์ต๋ ํ์ ๊น์ด (๊ธฐ๋ณธ๊ฐ: 4)-w, --window <window>: inspect ๋์ ์ฐฝ ์ธ๋ฑ์ค (๊ธฐ๋ณธ๊ฐ: main window)--show-attributes: ๊ฐ ์์์ AX attribute ์ถ๋ ฅ--show-path: ๊ฐ ์์์ AX ๊ฒฝ๋ก ์ถ๋ ฅ--show-frame: ๊ฐ ์์ frame ์ถ๋ ฅ--show-index: sibling index ์ถ๋ ฅ--show-flags: ์ํ ํ๋๊ทธ(enabled/focused/selected/editable) ์ถ๋ ฅ--show-actions: ์ง์ AX action ์ถ๋ ฅ--debug-layout:path/frame/index/flags๋ฅผ ํ ๋ฒ์ ์ผ๋ ๋ ์ด์์ ๋๋ฒ๊ทธ ๋ฒ๋ค--row-summary: ๋ฉ์์ง row ์์ฝ ์ถ๋ ฅ--row-range <start:end>:--row-summary๊ฒฐ๊ณผ๋ฅผ ํน์ ๋ฒ์๋ง ์ถ๋ ฅ (inclusive, zero-based)
kmsg help cachestatus(default): ์บ์ ์ํ ์ถ๋ ฅclear: ์บ์ ์ญ์ export <output-path>: ์บ์ JSON ๋ด๋ณด๋ด๊ธฐimport <input-path>: ์บ์ JSON ๊ฐ์ ธ์ค๊ธฐwarmup [--recipient <recipient>] [--trace-ax] [--keep-window]:send/chatshappy-path ๊ฒฝ๋ก ์บ์ ์๋ฐ์
kmsg๋ ์์ฌ์ด ์ฌ์ฉ(Accessibility) ๊ถํ์ด ํ์ํฉ๋๋ค.
์ฑ์ด ์๋ ์์ฒญ์ ์คํจํ๋ฉด:
- ์์คํ ์ค์ ์ด๊ธฐ
๊ฐ์ธ์ ๋ณด ๋ณดํธ ๋ฐ ๋ณด์ > ์์ฌ์ด ์ฌ์ฉkmsgํ ๊ธ ์ผ๊ธฐ
read ๋ช
๋ น์ --json ํ๋๊ทธ๋ก ๊ตฌ์กฐํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
kmsg read "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --limit 20 --json{
"chat": "ํ๊ธธ๋",
"fetched_at": "2026-02-26T01:23:45.678Z",
"count": 20,
"messages": [
{
"author": "ํ๊ธธ๋",
"time_raw": "00:27",
"body": "๋ฐค์ด ๊น์๋ค"
}
]
}chat: ์ค์ ๋ก ์ฝ์ ์ฑํ ๋ฐฉ ์ ๋ชฉfetched_at: ๋ฉ์์ง ์์ง ์๊ฐ(ISO-8601 UTC)count: ๋ฐํ๋ ๋ฉ์์ง ๊ฐ์messages[].author: ์์ฑ์ ์ด๋ฆ ((me)๋ ๋ด ๋ฉ์์ง ๋๋ ์์ฑ์ ์ถ๋ก ์ด ๋ถ๊ฐ๋ฅํ ๊ฒฝ์ฐ)messages[].time_raw: UI์์ ์ฝํ ์๊ฐ ๋ฌธ์์ด(์์ผ๋ฉดnull)messages[].body: ๋ฉ์์ง ๋ณธ๋ฌธ
--json์ฌ์ฉ ์ JSON์stdout์ผ๋ก๋ง ์ถ๋ ฅ๋ฉ๋๋ค.--trace-ax๋ก๊ทธ๋stderr๋ก ๋ถ๋ฆฌ๋๋ฏ๋ก OpenClaw ๊ฐ์ ํ์ดํ ์ฐ๋์์ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
watch --json์ ๋ฐฐ์ด ํ๋๋ฅผ ๋ฐํํ๋ ๋์ , ์ ๋ฉ์์ง๊ฐ ๊ฐ์ง๋ ๋๋ง๋ค pretty JSON ๊ฐ์ฒด ํ๋์ฉ์ ์ฐ์ ์ถ๋ ฅํฉ๋๋ค.
kmsg watch "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --json์์ ์ด๋ฒคํธ:
{
"chat": "ํ๊ธธ๋",
"detected_at": "2026-03-25T10:20:30.123Z",
"event": "message",
"message": {
"author": "ํ๊ธธ๋",
"time_raw": "10:20",
"body": "์ ๋ฉ์์ง"
}
}--include-system์ ๊ฐ์ด ์ฐ๋ฉด event ๊ฐ์ด system์ธ ๊ฐ์ฒด๋ ํจ๊ป ์ถ๋ ฅ๋ ์ ์์ต๋๋ค.
chats --json๋ ๋์ผํ๊ฒ stdout์๋ง JSON์ ์ถ๋ ฅํ๋ฉฐ, ๊ฐ ์ฑํ
ํญ๋ชฉ์ chat_id์ last_message๋ฅผ ํฌํจํฉ๋๋ค. ์ฒซ ์คํ์ด๋ ์บ์ self-heal ์์๋ ๋ ๋๋ฆด ์ ์์ง๋ง, ์ดํ ์คํ์ ์ ์ฅ๋ happy-path AX cache๋ฅผ ์ฐ์ ์ฌ์ฉํฉ๋๋ค.
kmsg ๋ MCP ๋ก ๋ถ์ฌ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ์ฌ ๊ตฌ์กฐ๋ ๋ค์์ฒ๋ผ ๋๋ฉ๋๋ค.
- MCP:
kmsg_read,kmsg_send,kmsg_send_image - ์ค์๊ฐ ๊ฐ์:
kmsg watch "<chat>" --json
์ฆ, OpenClaw ์ฐ๋์ ๋ณดํต ์๋ ๋ ํ๋ก์ธ์ค๋ก ๊ตฌ์ฑํฉ๋๋ค.
kmsg mcp-server
kmsg watch "์ฑํ
๋ฐฉ ์ด๋ฆ" --jsonOpenClaw MCP ์ค์ ์์:
{
"mcpServers": {
"kmsg": {
"command": "kmsg",
"args": ["mcp-server"],
"env": {
"KMSG_DEFAULT_DEEP_RECOVERY": "false",
"KMSG_TRACE_DEFAULT": "false"
}
}
}
}์ถ์ฒ ์ด์ ์์๋ ์๋์ ๊ฐ์ต๋๋ค.
watch --json์ผ๋ก ์ ๋ฉ์์ง ๊ฐ์ง- OpenClaw ๊ฐ ๋ต๋ณ ์ด์ ์์ฑ
- ํ์ํ๋ฉด ์ฌ์ฉ์ ์น์ธ
kmsg_send๋๋kmsg send๋ก ์ ์ก
์์ธ ์ด์ ๊ฐ์ด๋๋ docs/openclaw.md ๋ฅผ ์ฐธ๊ณ ํ์ธ์. ์ค์ ํ ํ๋ฆฟ์ docs/openclaw.mcp.example.json ์ ์์ต๋๋ค.
๊ธฐ์กด tools/kmsg-mcp.py ๋ ๋ ๊ฑฐ์/๊ฐ๋ฐ์ฉ ์ฐธ์กฐ ๊ตฌํ์ผ๋ก ๋จ์ ์์ง๋ง, ์ค์นํ ์ฌ์ฉ ํ๋ฆ์ ๊ธฐ๋ณธ ์ง์
์ ์ kmsg mcp-server ์
๋๋ค.
git clone https://github.com/channprj/kmsg.git
cd kmsg
swift build -c release
install -m 755 .build/release/kmsg ~/.local/bin/kmsgkmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ" --trace-ax
kmsg send --chat-id "chat_7f42c5e1d9ab" "ํ
์คํธ" --dry-run
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ" --dry-run --trace-ax
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ" --no-cache
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ" --refresh-cache
kmsg chats --json
kmsg send-image "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "/path/to/image.png" --trace-ax
KMSG_AX_TIMEOUT=0.25 kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ"
kmsg inspect --window 0 --depth 20 --debug-layout
kmsg inspect --window 0 --depth 20 --row-summary
kmsg inspect --window 0 --depth 20 --row-summary --row-range 10:35
kmsg cache status
kmsg cache warmup --recipient "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --trace-ax
kmsg cache warmup --recipient "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --keep-window
kmsg cache export ./ax-cache.json
kmsg cache import ./ax-cache.json
kmsg read "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --deep-recovery --trace-ax
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ" --deep-recovery --trace-ax
kmsg send-image "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "/path/to/image.png" --deep-recovery --trace-ax --keep-window--deep-recovery๋ ๋น ๋ฅธ ์ฐฝ ํ์์ด ์คํจํ ๋๋ง relaunch/open ๋ณต๊ตฌ๋ฅผ ์ถ๊ฐ๋ก ์ํํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์๋์ผ๋ก ์ฐ ์นด์นด์คํก ์ฐฝ์ ๋ช
๋ น ์ข
๋ฃ ์ ๋ซํ๋ฉฐ, --keep-window(๋๋ -k)๋ก ์ ์งํ ์ ์์ต๋๋ค.
๋ฉ์์ง ์ฝ๊ธฐ/๋ณด๋ด๊ธฐ๊ฐ ๊ธฐ๋์ ๋ค๋ฅด๋ฉด ์๋ ์์๋ก ์ํ๋ฅผ ์์งํด ์ฃผ์ธ์.
# 1) ๋์ ์ฑํ
์ฐฝ ๊ตฌ์กฐ ํ์ธ
kmsg inspect --window 0 --depth 20 --debug-layout
# 1-1) ๋ฉ์์ง row ํ์ฑ ์ง๋จ
kmsg inspect --window 0 --depth 20 --row-summary
kmsg inspect --window 0 --depth 20 --row-summary --row-range 10:30
# 2) ์ฝ๊ธฐ ๊ฒฝ๋ก/AX ๋ก๊ทธ ํ์ธ
kmsg read "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" --limit 20 --trace-ax
# 3) ๋ณด๋ด๊ธฐ ๊ฒฝ๋ก/AX ๋ก๊ทธ ํ์ธ
kmsg send "๋ณธ์ธ, ์น๊ตฌ, ๋๋ ๋จํก๋ฐฉ ์ด๋ฆ" "ํ
์คํธ" --trace-ax --dry-runAXTextArea, value: "..."๋ ์ค์ ๋ฉ์์ง ๋ณธ๋ฌธ ํ๋ณด์ ๋๋ค.AXStaticText, value: "5\n00:27"๊ฐ์ ๊ฐ์ ๋ณดํต ์นด์ดํธ/์๊ฐ ๋ฉํ ์ ๋ณด์ ๋๋ค.--debug-layout์ ์ผ๋ฉดpath/frame/index/flags๊ฐ ํจ๊ป ์ถ๋ ฅ๋์ด ์์น ๊ธฐ๋ฐ ๋ถ์์ด ์ฌ์์ง๋๋ค.--row-summary๋readํ์ ๊ธฐ์ค์ผ๋ก row๋ณauthorCandidates,time,buttonTitles๋ฅผ ๋น ๋ฅด๊ฒ ์ ๊ฒํ ๋ ์ ์ฉํฉ๋๋ค.- ์ด์ ๋ณด๊ณ ์
inspect์ถ๋ ฅ๊ณผ--trace-ax์ถ๋ ฅ์ ํจ๊ป ์ฒจ๋ถํ๋ฉด ์์ธ ํ์ ์ด ๋นจ๋ผ์ง๋๋ค.
๊ฐ๋ฐ์ ์งํํ๊ฑฐ๋ ๋ฒ๊ทธ ์์ ์ ์ํ ๋ Coding Agent์๊ฒ ์๋ ์ ๋ณด์ ํจ๊ป ์์ฒญํ๋ฉด ์ข์ต๋๋ค.
- ์คํํ ๋ช
๋ น์ด:
kmsg read ... --trace-ax,kmsg inspect ... - ๊ธฐ๋ ๊ฒฐ๊ณผ: ๋ฌด์์ด ๋ณด์ฌ์ผ ํ๋์ง
- ์ค์ ๊ฒฐ๊ณผ: ํ์ฌ ๋ฌด์์ด ์ถ๋ ฅ๋๋์ง
- ๊ด๋ จ ๋ก๊ทธ:
inspect๋ณธ๋ฌธ ๊ตฌ๊ฐ (AXRow > AXCell > AXTextArea) +trace-ax
kmsg read๊ฐ ๋ฉ์์ง ๋ณธ๋ฌธ ๋์ ์๊ฐ/์ซ์๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
inspect ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์ค์ผ๋ก AXRow > AXCell > AXTextArea.value๋ฅผ ์ฐ์ ์ถ์ถํ๋๋ก ์์ ํด ์ฃผ์ธ์.
README ๋๋ฒ๊น
๊ฐ์ด๋๋ ํจ๊ป ์
๋ฐ์ดํธํด ์ฃผ์ธ์.
v* ํ๊ทธ๋ฅผ ํธ์ํ๋ฉด GitHub Actions๊ฐ ์๋์ผ๋ก ๋น๋ํด์ kmsg-macos-universal ํ์ผ์ Releases์ ์
๋ก๋ํฉ๋๋ค.
๊ฐ์ workflow๊ฐ channprj/homebrew-tap ๋ฆฌ๋ชจํธ๊น์ง ์๋์ผ๋ก ๋๊ธฐํํ๋ฉฐ, TAP_REPO_TOKEN์ด ์๊ฑฐ๋ tap push๊ฐ ์คํจํ๋ฉด ๋ฆด๋ฆฌ์ฆ๋ ์คํจํฉ๋๋ค.
๋ฐฐํฌ ์ ์ VERSION ํ์ผ ๊ฐ์ ๋จผ์ ์
๋ฐ์ดํธํ์ธ์.
๋ฒ์ ๊ท์น์ VERSIONING.md๋ฅผ ๋ฐ๋ฆ
๋๋ค.
# gh ํ ํฐ์ด ๋ง๋ฃ๋์ผ๋ฉด ์ฌ๋ก๊ทธ์ธ
gh auth login -h github.com
# ๋ฐฐํฌ ํ๊ทธ ์์ฑ/ํธ์
git tag v2026.0422.22
git push origin v2026.0422.22ํ์ํ๋ฉด Actions๋ฅผ ์๋ ์คํํ ์ ์์ต๋๋ค.
workflow_dispatch์์ tag๋ฅผ ๋น์๋๋ฉด VERSION ํ์ผ์ ์ฝ์ด v<version>์ผ๋ก ์๋ ์์ฑํฉ๋๋ค.
tag๋ฅผ ์ง์ ์
๋ ฅํ ๊ฒฝ์ฐ vYYYY.MMDD.COUNT ํ์๋ง ํ์ฉ๋ฉ๋๋ค.
# ํ๊ทธ๋ฅผ ์ง์ ์ง์ ํด์ ์คํ
gh workflow run release.yml -f tag=v2026.0422.22
# tag ๋ฏธ์ง์ ์ VERSION(์: 2026.0422.22) ๊ธฐ๋ฐ์ผ๋ก ์คํ
gh workflow run release.ymlchannprj/homebrew-tap์ ์ฅ์๋ฅผ ๋ง๋ค๊ณFormula/๋๋ ํฐ๋ฆฌ๋ฅผ ์ค๋นํฉ๋๋ค.kmsg์ ์ฅ์ Secrets์TAP_REPO_TOKEN์ ์ถ๊ฐํฉ๋๋ค.- ๊ถํ:
homebrew-tap์ ์ฅ์contents: write
- ๊ถํ:
- tap ์ ์ฅ์ ๊ธฐ๋ณธ ๋ธ๋์น๊ฐ
main์ด ์๋๋ฉด.github/workflows/release.yml์TAP_REPO_REF๊ฐ์ ๋ง์ถฐ ์ฃผ์ธ์.
์ด์ TAP_REPO_TOKEN์ ์ ํ์ด ์๋๋ผ ํ์์
๋๋ค.
secret์ด ์์ผ๋ฉด ๋ฐ์ด๋๋ฆฌ release๋ง ๋ง๋ค๊ณ ๋๋ด์ง ์๊ณ , workflow ์ ์ฒด๊ฐ ์คํจํด์ tap ๋ฐ์ ๋๋ฝ์ ๋ฐ๋ก ์ก๋๋ก ๋์ํฉ๋๋ค.
๋ฆด๋ฆฌ์ฆ ํ ์ฌ์ฉ์๋ ์๋ ๋ช ๋ น์ผ๋ก ์ค์นํ ์ ์์ต๋๋ค.
brew install channprj/tap/kmsg
brew install channprj/tap/kmsg@2026.0422.22kmsg formula๋ ํญ์ ์ต์ ๋ฆด๋ฆฌ์ฆ๋ฅผ ๊ฐ๋ฆฌํค๊ณ , kmsg@YYYY.MMDD.COUNT formula๋ ์ต๊ทผ 10๊ฐ exact release๋ง ์ ์ง๋ฉ๋๋ค.
์ด๋ฏธ ๋ค๋ฅธ ๋ฒ์ ์ ์ค์นํ๋ค๋ฉด ์๋์ฒ๋ผ ๋งํฌ๋ฅผ ์ ํํ ์ ์์ต๋๋ค.
brew unlink kmsg
brew link --overwrite kmsg@2026.0422.22kmsg ๋ macOS ์ ์ฉ ๋๊ตฌ์ด๊ณ , ํต์ฌ ๊ธฐ๋ฅ์ด AppKit, ApplicationServices, AXUIElement, CGEvent ๊ฐ์ macOS native API ์์ ์ฌ๋ผ๊ฐ ์์ต๋๋ค. Swift ๋ ์ด API ๋ค๊ณผ์ ์ฐ๊ฒฐ์ด ๊ฐ์ฅ ์ง์ ์ ์ด๊ณ ์์ ์ ์ด๋ฉฐ, Objective-C ๊ณ์ด ํ๋ ์์ํฌ์์ ์ํธ์ด์ฉ๋ ์์ฐ์ค๋ฝ์ต๋๋ค.
๋ฐ๋๋ก Python ์ ๋ฐํ์/๋ฐฐํฌ ์์กด์ฑ์ด ๋์ด๋๊ณ , Rust ๋ macOS framework binding ๊ณผ FFI ๊ด๋ฆฌ ๋ณต์ก๋๊ฐ ์ปค์ง๊ธฐ ๋๋ฌธ์ ํ์ฌ ๋ชฉ์ ์๋ Swift ์ชฝ์ด ๊ตฌํ๊ณผ ์ ์ง๋ณด์ ๋ชจ๋ ๋ ์ค์ฉ์ ์ด์์ต๋๋ค.
AX ๋ macOS Accessibility(์์ฌ์ด ์ฌ์ฉ) API ๋ฅผ ๋ปํฉ๋๋ค. ์ฑ์ ์ฐฝ, ๋ฒํผ, ์
๋ ฅ์ฐฝ, ํ
์คํธ ๊ฐ์ UI ์์๋ฅผ AXUIElement ๋ก ์ฝ๊ณ ์ ์ดํ ์ ์๊ฒ ํด์ฃผ๋ ์์คํ
์ธํฐํ์ด์ค์
๋๋ค.
KakaoTalk ์ ๊ณต์์ ์ผ๋ก CLI ๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค. ๊ทธ๋์ ์ค์ ์ฌ์ฉ์๊ฐ ๋ณด๊ณ ํด๋ฆญํ๋ UI ๋ฅผ ์์คํ
๋ ๋ฒจ์์ ์ฝ๊ณ ์กฐ์ํ ์ ์๋ ํ์ค์ ์ธ ๋ฐฉ๋ฒ์ด AX ์
๋๋ค.
kmsg ์ ์ฑํ
๋ชฉ๋ก ์ฝ๊ธฐ, ๊ฒ์, ๋ฉ์์ง ์ ์ก, ์ด๋ฏธ์ง ์ ์ก, ์ฐฝ ์ ์ด๊ฐ ๋ชจ๋ ์ด ๋ ์ด์ด ์์์ ๋์ํ๊ธฐ ๋๋ฌธ์ Accessibility permission ์ด ํ์ํฉ๋๋ค.
LOCO Protocol ์ ์ฐ๋ ค๋ฉด ์ฌ์ค์ ๋น๊ณต๊ฐ ๋์์ ๋ฆฌ๋ฒ์ค ์์ง๋์ด๋งํด์ผ ํ๋๋ฐ, ์ ๋ ์ด ์ ๊ทผ์ด ๋ช ๋ฐฑํ ์ฝ๊ด ์๋ฐ์ผ๋ก ํด์๋ ์ฌ์ง๊ฐ ํฌ๋ค๊ณ ๋ด ๋๋ค. ์ค์ ๋ก ์ด๋ฐ ๋ฐฉ์์ ์๋ํ๋ ๋น๊ณต์ ํ๋กํ ์ฝ ์ฌ์ฉ๊ณผ ๊ด๋ จํด ๊ณ์ ์ด ์๊ตฌ์ ์ง๋ ์ฌ๋ก๋ ์ด๋ฏธ ์ ์ง ์๊ฒ ์๋ ค์ ธ ์์ด์, ๊ธฐ๋ฅ์ ์ผ๋ก ๊ฐ๋ฅํ๋๋ผ๋ ๊ฐ์ํด์ผ ํ๋ ๋ฆฌ์คํฌ๊ฐ ๋๋ฌด ํฌ๋ค๊ณ ํ๋จํ์ต๋๋ค.
๋ฐ๋ฉด AX ๋ฐฉ์์ ์ฌ์ฉ์๊ฐ ์ค์ ๋ก ๋ณด๊ณ ์กฐ์ํ๋ KakaoTalk UI ๋ฅผ macOS ์ ๊ณต์ Accessibility API ๋ก ์ฝ๊ณ ์ ์ดํ๋ ์ ๊ทผ์ด๋ผ, ์ ์ด๋ LOCO ๋ฅผ ์ง์ ๊ฑด๋๋ฆฌ๋ ๋ฐฉ์๋ณด๋ค๋ ์๋์ ์ผ๋ก ์์ ํ ๊ฒ์ด๋ผ๊ณ ํ๋จํ์ต๋๋ค. ๋ค๋ง ์ด๊ฒ๋ ์ด๋๊น์ง๋ ์ ๊ฐ์ธ์ ์ธ ํ๋จ์ผ ๋ฟ์ด๋ฉฐ, ์นด์นด์ค์ ๊ณต์ ์ ์ฅ์ด๋ ์นด์นด์ค ๋ฒ๋ฌดํ์ ํด์๊ณผ๋ ๋ค๋ฅผ ์ ์์ต๋๋ค. ์ค์ ์ฝ๊ด ํด์๊ณผ ์ ์ฌ ๊ธฐ์ค์ ์นด์นด์ค ์ธก ํ๋จ์ด ์ฐ์ ํฉ๋๋ค.
์กฐ๊ธ์ ๋นจ๋ผ์ง ์ ์์ง๋ง, ์ฒด๊ฐ ์ฑ๋ฅ ํฅ์์ ์ ํ์ ์ผ ๊ฐ๋ฅ์ฑ์ด ํฝ๋๋ค. ์ด CLI ์ ์ฃผ๋ ์ง์ฐ์ ์ธ์ด ๋ฐํ์๋ณด๋ค AXUIElement ํธ์ถ, UI ํ์, KakaoTalk ์ฐฝ ํ์ฑํ/๋ณต๊ตฌ, ์ค์ ์ฑ ์๋ต ์๊ฐ์์ ๋ฐ์ํฉ๋๋ค.
Rust ๋ก ๋ฐ๊พธ๋ฉด cold start ๋ ์์ stdio/JSON ์ฒ๋ฆฌ ๊ฐ์ ๋ถ๋ถ์ ์ฝ๊ฐ ์ ๋ฆฌํ ์ ์์ง๋ง, ์ ์ฒด end-to-end latency ๋ ํฌ๊ฒ ๋ฌ๋ผ์ง์ง ์์ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ๋์ macOS native framework binding ๊ณผ ์ ์ง๋ณด์ ๋น์ฉ์ Swift ๋ณด๋ค ๋์์ง ์ ์์ต๋๋ค.
This project is strongly inspired by steipete and his works.
