openkakao-cli
OpenKakao CLI
openkakao-rs is a KakaoTalk CLI with REST and LOCO support. Prefer LOCO commands for full history, sending, and real-time behavior. Prefer local-first automation unless the user explicitly wants events to leave the machine.
Quick checks
openkakao-rs --version
openkakao-rs auth
openkakao-rs auth-status
openkakao-rs doctor
If Homebrew install is needed:
brew tap JungHoonGhae/openkakao
brew install JungHoonGhae/openkakao/openkakao-rs
If the user seems to have an older binary than the repo docs or source imply, check:
which openkakao-rs
openkakao-rs --version
openkakao-rs send --help
openkakao-rs watch --help
Persistent operator policy can live in:
~/.config/openkakao/config.toml
Persisted runtime state now also lives in:
~/.config/openkakao/state.json
REST API Commands (read-only, cached token)
openkakao-rs login --save # Extract credentials from KakaoTalk's Cache.db
openkakao-rs auth # Verify token validity
openkakao-rs me # Show your profile
openkakao-rs friends [-f] [-s q] # List friends (favorites/search)
openkakao-rs settings # Show account settings
openkakao-rs chats # List chat rooms (Pilsner REST API)
openkakao-rs read <id> [-n N] [--all] # Read messages (Pilsner, limited cache)
openkakao-rs members <id> # List chat room members
LOCO Protocol Commands (full access, real-time)
openkakao-rs loco-test # Test full LOCO connection
openkakao-rs send <chat_id> <message> [-y] # Send text message via LOCO WRITE (add -y to skip prompt)
openkakao-rs send <chat_id> <message> -y --json # Send and get JSON response (v0.7.0+)
openkakao-rs send-photo <chat_id> <file> [-y] # Send photo (JPEG/PNG/GIF) via LOCO SHIP+POST
openkakao-rs send-file <chat_id> <file> [-y] # Send any file (photo/video/doc) via LOCO
openkakao-rs watch [--chat-id ID] [--raw] # Watch real-time incoming messages
openkakao-rs watch --json # Watch with NDJSON output (v0.7.0+)
openkakao-rs watch --read-receipt # Watch + send read receipts (NOTIREAD)
openkakao-rs watch --max-reconnect 10 # Auto-reconnect on disconnect (default 5)
openkakao-rs watch --download-media # Auto-download media attachments
openkakao-rs watch --resume # Resume from last saved watch state (v0.6.0+)
openkakao-rs watch --capture # Output unknown push packets as NDJSON for protocol RE (v0.9.0+)
openkakao-rs delete <chat_id> <log_id> [-y] # Delete a message via DELETEMSG (v0.9.0+)
openkakao-rs mark-read <chat_id> <log_id> # Mark messages read up to logId via NOTIREAD (v0.9.0+)
openkakao-rs react <chat_id> <log_id> [-t N] # Add reaction via ACTION (type=1=like, v0.9.1+)
openkakao-rs edit <chat_id> <log_id> <msg> [-y] # Edit message via REWRITE (macOS: -203, v0.9.2+)
openkakao-rs download <chat_id> <log_id> [-o D] # Download media from a specific message
openkakao-rs loco-chats [--all] # List all chat rooms
openkakao-rs loco-read <chat_id> [-n N] [--all] # Read message history (SYNCMSG)
openkakao-rs loco-read <chat_id> --all --json # JSON output
openkakao-rs loco-members <chat_id> # List members
openkakao-rs loco-chatinfo <chat_id> # Raw chat room info
JSON output (v0.7.0+)
All commands support --json (global flag). Key additions in v0.7.0:
send --json:{"chat_id": ..., "log_id": ..., "status": "sent"}send-file --json:{"chat_id": ..., "file": ..., "type": ..., "status": "sent"}delete --json:{"chat_id": ..., "log_id": ..., "status": "deleted"}(v0.9.0+)react --json:{"chat_id": ..., "log_id": ..., "reaction_type": ..., "status": "reacted"}(v0.9.1+)edit --json:{"chat_id": ..., "log_id": ..., "status": "edited"}(v0.9.2+, macOS: -203)mark-read --json:{"chat_id": ..., "watermark": ..., "status": "marked_read"}(v0.9.0+)watch --json: NDJSON stream, one JSON object per event linechats --json,read --json,members --json,stats --json: already supported pre-v0.7.0
Analytics & Local Cache (v0.5.0+)
openkakao-rs stats <chat_id> # Message counts, hourly activity histogram, top senders
openkakao-rs cache <chat_id> [-n N] # Sync messages to local SQLite cache
openkakao-rs cache-search <query> # Full-text search across cached messages
openkakao-rs cache-stats # Show local cache statistics (row counts, db size)
LOCO vs REST for messages
- REST (
read): Uses Pilsner cache — only returns messages for recently opened chats in the KakaoTalk app. Many chats return empty. - LOCO (
loco-read): Uses SYNCMSG protocol — returns all server-retained messages. Preferred for full history access. - Local cache merge (v0.9.3+):
readautomatically merges LOCO results with locally cached messages fromwatch. Messages captured during watch sessions appear in subsequent reads even when LOCO returns a limited window.
Token Management
openkakao-rs relogin [--fresh-xvc] # Refresh token via login.json + X-VC
openkakao-rs renew # Attempt token renewal via refresh_token
openkakao-rs watch-cache [--interval N] # Poll Cache.db for fresh tokens
openkakao-rs auth-status # Show persisted auth recovery state and cooldowns
openkakao-rs doctor [--loco] # Environment, token, recovery, and safety diagnostics
LOCO commands automatically refresh tokens via login.json + X-VC when needed, and REST/LOCO now share the same persisted recovery state.
Workflow (LOCO-first)
- Quick sanity:
openkakao-rs --version && openkakao-rs loco-test - Get chat IDs:
openkakao-rs loco-chats --all --json(note:--allcan be slower) - Send message:
openkakao-rs send -y <chat_id> "message text"(default prefix on; add--no-prefixto disable) - Read messages:
openkakao-rs loco-read <chat_id> -n 50(or--all) - Only when you need REST-only features: open KakaoTalk app →
openkakao-rs login --save→openkakao-rs auth
Watch automation workflow
Use this order:
- Confirm
watchbehavior first:openkakao-rs watch --help - Start local-only with
--hook-cmd - Add filters:
--hook-chat-id--hook-keyword--hook-type
- Only then move to
--webhook-urlif the user explicitly wants external delivery - If using a webhook, prefer
--webhook-signing-secretand tell the user to verify:X-OpenKakao-TimestampX-OpenKakao-Signature
Local-first example:
openkakao-rs watch \
--hook-cmd 'jq . > /tmp/openkakao-event.json' \
--hook-chat-id 382416827148557 \
--hook-type 1
Webhook example:
openkakao-rs watch \
--webhook-url https://hooks.example.com/openkakao \
--webhook-header 'Authorization: Bearer token' \
--webhook-signing-secret 'super-secret' \
--hook-keyword urgent
Unattended and policy gates
OpenKakao separates:
--unattended: declare non-interactive operation--allow-non-interactive-send: allowsend -y,send-file -y,send-photo -y,edit -y--allow-watch-side-effects: allowwatch --read-receipt,--hook-cmd,--webhook-url--completion-promise: print[DONE]to stdout after successful command completion (v0.9.2+, useful for LLM agent integration)
Recommended persistent config:
[mode]
unattended = true
[send]
allow_non_interactive = true
default_prefix = true
[watch]
allow_side_effects = true
default_max_reconnect = 10
[auth]
prefer_relogin = true
auto_renew = true
[safety]
min_unattended_send_interval_secs = 10
min_hook_interval_secs = 2
min_webhook_interval_secs = 2
hook_timeout_secs = 20
webhook_timeout_secs = 10
allow_insecure_webhooks = false
Interpretation:
- unattended sends are rate-limited by default
- local hooks are rate-limited and timed out
- webhooks are rate-limited, timed out, and default to HTTPS only unless localhost
auth-statusanddoctorare the first checks before assuming a long-running job is healthy
Speed tips
- Prefer LOCO for send/read/history — REST token expiry +
login --savecan block waiting on Cache.db. - Cache
chat_ids you use often; avoid runningloco-chats --allrepeatedly. - Use
-y/--yesfor non-interactive sends when you're confident thechat_idis correct.
Multiline (줄바꿈) 메시지 보내기
주의: 커맨드라인에서 \n을 그냥 쓰면 줄바꿈이 아니라 문자 그대로 \n이 전송될 수 있음. 실제 개행 문자를 만들어서 인자로 넘겨야 함.
예시:
- bash/zsh:
openkakao-rs send -y <chat_id> "$(printf '첫줄\n\n둘째줄')"
- bash 전용($'' quoting):
openkakao-rs send -y <chat_id> $'첫줄\n\n둘째줄'
- fish:
openkakao-rs send -y <chat_id> (printf '첫줄\n\n둘째줄')
Troubleshooting
Token invalid or -950 error
# Open KakaoTalk app first, then:
openkakao-rs login --save
openkakao-rs auth
openkakao-rs auth-status
LOCO commands auto-refresh tokens, so -950 is usually handled automatically.
If the machine has been running unattended for a while, inspect:
openkakao-rs auth-status --jsonopenkakao-rs doctor --loco
Look for:
last_failure_kindconsecutive_failuresauth_cooldown_remaining_secslast_recovery_source
login --save seems to hang
login --save may wait until KakaoTalk updates Cache.db.
- Open KakaoTalk → open the chat list once (forces a cache refresh)
- (Optional)
openkakao-rs watch-cache --interval 2to see when tokens change - Or skip REST entirely and use LOCO (
loco-test/send/loco-read).
GETMSGS returns -300
This is expected on Mac (dtype=2). Use loco-read (SYNCMSG) instead of REST read (GETMSGS).
Homebrew formula not found
brew tap JungHoonGhae/openkakao
brew update
brew install JungHoonGhae/openkakao/openkakao-rs
Guardrails
- Prefix/traceability: By default,
openkakao-rsprepends🤖 [Sent via openkakao]to outgoing messages. Use--no-prefixto disable it.- If you want a custom tag (e.g.
🤖 [openkakao]), either add it in the message text (and keep default prefix), or disable the default prefix and add your own — avoid double-prefixing unless you want it.
- If you want a custom tag (e.g.
- Use
-y/--yesonly when you are sure thechat_idis correct. - Do not assume unattended send can burst freely; the CLI now rate-limits it by default.
- Avoid
--forceunless you know what you're doing (higher ban risk). - Prefer
watch --hook-cmdover webhooks when the task can stay on the same machine. - If using
--webhook-url, be explicit that chat content leaves the local trust boundary. - Expect non-HTTPS remote webhooks to be blocked unless the user has explicitly loosened
safety.allow_insecure_webhooks. - Treat
watchhooks/webhooks as best-effort delivery, not a durable queue or exactly-once event bus. - Treat unattended mode as a policy decision. If the user is building a service, push them toward
config.tomlinstead of repeating long flag strings. - For macOS services, steer users toward
examples/launchd/in the repo instead of ad-hoc LaunchAgent files. - Do not expose personal chat content unless the user explicitly asks.
- Prefer summary/aggregation output for logs and reports.