Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
LINE messaging integration via Chrome extension gateway. Send/read LINE messages, manage contacts, groups, profile, and reactions. Authenticate with QR code...
LINE messaging integration via Chrome extension gateway. Send/read LINE messages, manage contacts, groups, profile, and reactions. Authenticate with QR code...
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
Full LINE messaging client via the Chrome extension gateway JSON API.
Repo: /data/workspace/line-client (github.com/2manslkh/line-api) Main client: src/chrome_client.py → LineChromeClient QR login: src/auth/qr_login.py → QRLogin HMAC signer: src/hmac/signer.js (Node.js, auto-starts on port 18944) Token storage: ~/.line-client/tokens.json Certificate cache: ~/.line-client/sqr_cert WASM files: lstm.wasm + lstmSandbox.js (required, in repo root)
import json from pathlib import Path from src.chrome_client import LineChromeClient tokens = json.loads((Path.home() / ".line-client" / "tokens.json").read_text()) client = LineChromeClient(auth_token=tokens["auth_token"]) # Send a message client.send_message("U...", "Hello!") # Get profile profile = client.get_profile() Tokens expire in ~7 days. If expired (APIError(10051)), re-run QR login.
QR login requires user interaction: scan QR on phone + enter PIN. from src.hmac import HmacSigner from src.auth.qr_login import QRLogin import qrcode signer = HmacSigner(mode="server") login = QRLogin(signer) result = login.run( on_qr=lambda url: send_qr_image_to_user(qrcode.make(url)), on_pin=lambda pin: send_pin_to_user_IMMEDIATELY(pin), # TIME SENSITIVE! on_status=lambda msg: print(msg), ) # result.auth_token, result.mid, result.refresh_token Critical: The PIN must reach the user within ~60 seconds. Send it the instant on_pin fires.
createSession → session ID createQrCode → callback URL (append ?secret={curve25519_pubkey}&e2eeVersion=1) checkQrCodeVerified — poll until scan (uses X-Line-Session-ID, no origin header) verifyCertificate — MUST be called even if it fails (required state transition!) createPinCode → 6-digit PIN (skip if cert verified in step 4) checkPinCodeVerified — poll until user enters PIN qrCodeLoginV2 → JWT token + certificate + refresh token
python scripts/qr_login_server.py /tmp/qr.png Emits JSON events on stdout: {"event": "qr", "path": "...", "url": "..."}, {"event": "pin", "pin": "123456"}, {"event": "done", "mid": "U..."}.
MethodArgsDescriptionget_profile()—Get your own profile (displayName, mid, statusMessage, etc.)get_contact(mid)mid: strGet a single contact's profileget_contacts(mids)mids: list[str]Get multiple contactsget_all_contact_ids()—List all friend MIDsfind_contact_by_userid(userid)userid: strSearch by LINE IDfind_and_add_contact_by_mid(mid)mid: strAdd friend by MIDfind_contacts_by_phone(phones)phones: list[str]Search by phone numbersadd_friend_by_mid(mid)mid: strAdd friend (RelationService)get_blocked_contact_ids()—List blocked MIDsget_blocked_recommendation_ids()—List blocked recommendationsblock_contact(mid)mid: strBlock a contactunblock_contact(mid)mid: strUnblock a contactblock_recommendation(mid)mid: strBlock a friend suggestionupdate_contact_setting(mid, flag, value)mid, flag: int, value: strUpdate contact setting (e.g. mute)get_favorite_mids()—List favorited contact MIDsget_recommendation_ids()—List friend suggestions
MethodArgsDescriptionsend_message(to, text, ...)to: str, text: str, reply_to: str (opt)Send a text message. Supports replies via reply_to=message_idunsend_message(message_id)message_id: strUnsend/delete a sent messageget_recent_messages(chat_id, count=50)chat_id: strGet latest messages in a chatget_previous_messages(chat_id, end_seq, count=50)chat_id, end_seq: intPaginated history (older messages)get_messages_by_ids(message_ids)message_ids: list[str]Fetch specific messagesget_message_boxes(count=50)—Get chat list with last message (inbox view)get_message_boxes_by_ids(chat_ids)chat_ids: list[str]Get specific chats with last messageget_message_read_range(chat_ids)chat_ids: list[str]Get read receipt infosend_chat_checked(chat_id, last_message_id)chat_id, last_message_id: strMark messages as readsend_chat_removed(chat_id, last_message_id)chat_id, last_message_id: strRemove chat from inboxsend_postback(to, postback_data)to, postback_data: strSend postback (bot interactions)
MethodArgsDescriptionget_chats(chat_ids, with_members=True, with_invitees=True)chat_ids: list[str]Get chat/group detailsget_all_chat_mids()—List all chat MIDs (groups + invites)create_chat(name, target_mids)name: str, target_mids: list[str]Create a new group chataccept_chat_invitation(chat_id)chat_id: strAccept group invitereject_chat_invitation(chat_id)chat_id: strReject group inviteinvite_into_chat(chat_id, mids)chat_id: str, mids: list[str]Invite users to groupcancel_chat_invitation(chat_id, mids)chat_id: str, mids: list[str]Cancel pending invitesdelete_other_from_chat(chat_id, mids)chat_id: str, mids: list[str]Kick members from groupleave_chat(chat_id)chat_id: strLeave a group chatupdate_chat(chat_id, updates)chat_id: str, updates: dictUpdate group name/settingsset_chat_hidden_status(chat_id, hidden)chat_id: str, hidden: boolArchive/unarchive a chatget_rooms(room_ids)room_ids: list[str]Get legacy room infoinvite_into_room(room_id, mids)room_id: str, mids: list[str]Invite to legacy roomleave_room(room_id)room_id: strLeave legacy room
MethodArgsDescriptionreact(message_id, reaction_type)message_id: str, type: intReact to a message. Types: 2=like, 3=love, 4=laugh, 5=surprised, 6=sad, 7=angrycancel_reaction(message_id)message_id: strRemove your reaction
MethodArgsDescriptionupdate_profile_attributes(attr, value, meta={})attr: int, value: strUpdate profile. Attrs: 2=DISPLAY_NAME, 16=STATUS_MESSAGE, 4=PICTURE_STATUSupdate_status_message(message)message: strShortcut: update status messageupdate_display_name(name)name: strShortcut: update display nameget_settings()—Get all account settingsget_settings_attributes(attr_bitset)attr_bitset: intGet specific settingsupdate_settings_attributes(attr_bitset, settings)attr_bitset: int, settings: dictUpdate settings
MethodArgsDescriptionget_last_op_revision()—Get latest operation revision numberfetch_ops(count=50)—Fetch pending operations (may long-poll)poll()—Generator yielding operations as they arriveon_message(handler)handler: Callable(msg, client)Start polling thread, calls handler on new messages. Op types: 26=SEND_MESSAGE, 27=RECEIVE_MESSAGEstop()—Stop the polling thread
MethodArgsDescriptionget_server_time()—Get LINE server timestampget_configurations()—Get server configurationsget_rsa_key_info()—Get RSA key for authissue_channel_token(channel_id)channel_id: strIssue channel token (LINE Login/LIFF)get_buddy_detail(mid)mid: strGet official account inforeport_abuse(mid, category=0, reason="")mid: strReport a useradd_friend_by_mid(mid)mid: strAdd friend (RelationService)logout()—Logout and invalidate token
LINE identifies entities by MID: U... or u... → User (toType=0) C... or c... → Group chat (toType=2) R... or r... → Room (toType=1) The client auto-detects toType from the MID prefix when sending messages.
All API calls require X-Hmac header. The WASM signer handles this automatically: Derives key from version "3.7.1" + access token via proprietary KDF (in lstm.wasm) Signs path + body → base64 → X-Hmac Server mode: ~13ms/sign (Node.js HTTP server on port 18944, auto-started) Subprocess mode: ~2s/sign (fallback)
from src.chrome_client import APIError try: client.send_message(mid, "test") except APIError as e: print(e.code, e.api_message) # 10051 = session expired / invalid # 10052 = HTTP error from backend # 10102 = invalid arguments
User's Phone (LINE app) ↕ (scan QR / enter PIN) LINE Servers (line-chrome-gw.line-apps.com) ↕ (JSON REST + X-Hmac signing) LineChromeClient (this repo) ↕ (WASM HMAC via Node.js signer) lstm.wasm + lstmSandbox.js The Chrome Gateway translates JSON ↔ Thrift internally. We never deal with Thrift binary — everything is clean JSON.
Code helpers, APIs, CLIs, browser automation, testing, and developer operations.
Largest current source with strong distribution and engagement signals.