Source profileQuality 93/100

larksuite/cli/skills/lark-event/SKILL.md

lark-event

Lark/Feishu real-time event listening / subscribing / consuming: stream events as NDJSON via `lark-cli event consume <EventKey>` (covers IM messages/reactions/chat changes, Approval status changes, Task updates, VC meeting started/joined/ended, Minutes generated, Whiteboard updated, etc.). Use for Lark bots, real-time message processing, long-running subscribers, streaming webhook/push handlers. Supports `--max-events` / `--timeout` bounded runs and a stderr ready-marker contract — designed for

Source repository stars
16,128
Declared platforms
0
Static risk flags
1
Last source update
2026-08-04
Source checked
2026-08-04

Decision brief

What it does—and where it fits

Prerequisite: Read ../lark-shared/SKILL.md first for authentication, --as user/bot switching, Permission denied handling, and safety rules.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/larksuite/cli --skill "skills/lark-event"
    Safe inspection promptEditorial

    Inspect the Agent Skill "lark-event" from https://github.com/larksuite/cli/blob/811d37e57b4328453ecd5a7c3814e790c2f13921/skills/lark-event/SKILL.md at commit 811d37e57b4328453ecd5a7c3814e790c2f13921. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Consume multiple EventKeys concurrently (one shape per process, no dispatcher)

      lark-cli event consume im.message.receivev1 --as bot receive.ndjson & lark-cli event consume im.message.reaction.createdv1 --as bot reaction.ndjson & wait

      lark-cli event consume im.message.receivev1 --as bot receive.ndjson & lark-cli event consume im.message.reaction.createdv1 --as bot reaction.ndjson & waitjson { "chatid": {"type":"string", "format":"chatid", "description":"Chat ID, prefixed with oc"}, "senderid": {"type":"string", "format":"openid", "description":"Sender openid, prefixed with ou"}, "createtime": {"type":…(3) Field semantics — see the format tag
    2. 02

      Core commands

      Review the “Core commands” section in the pinned source before continuing.

      Review and apply the “Core commands” source section.
    3. 03

      Common flags

      Review the “Common flags” section in the pinned source before continuing.

      Review and apply the “Common flags” source section.
    4. 04

      Examples

      Review the “Examples” section in the pinned source before continuing.

      Review and apply the “Examples” source section.
    5. 05

      Default: stream every event for the key (no filter, no projection)

      lark-cli event consume im.message.receivev1 --as bot

      lark-cli event consume im.message.receivev1 --as bot

    Permission review

    Static risk signals and limitations

    Writes files

    medium · line 25

    The documentation asks the agent to create, modify, or delete local files.

    | `--output-dir <dir>` | Write each event as a file (relative paths only; prevents traversal) |

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score93/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars16,128SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    larksuite/cli
    Skill path
    skills/lark-event/SKILL.md
    Commit
    811d37e57b4328453ecd5a7c3814e790c2f13921
    License
    MIT
    Collected
    2026-08-04
    Default branch
    main
    View the original SKILL.md

    Lark Events

    Prerequisite: Read ../lark-shared/SKILL.md first for authentication, --as user/bot switching, Permission denied handling, and safety rules.

    Core commands

    CommandPurpose
    lark-cli event list [--json]List all subscribable EventKeys
    lark-cli event schema <EventKey> [--json]Show an EventKey's params and output schema
    lark-cli event consume <EventKey> [flags]Blocking consume; events → stdout NDJSON
    lark-cli event status [--json] [--fail-on-orphan]Inspect the local bus daemon status
    lark-cli event stop [--all] [--force]Stop the bus daemon

    Common flags

    FlagDescription
    --param key=value / -pBusiness params (repeatable; comma-separated for multi-value). Unknown keys fail with valid names listed inline
    --jq <expr>jq expression to filter / transform each event; empty output skips the event
    --max-events NExit after N events. Default 0 = unlimited
    --timeout DExit after duration D (e.g. 30s, 2m). Default 0 = no timeout. Whichever of --max-events / --timeout fires first wins
    --output-dir <dir>Write each event as a file (relative paths only; prevents traversal)
    --quietSuppress stderr diagnostics. AI should not use this — it silences the ready marker
    --as user|bot|autoIdentity for the session (see lark-shared)

    Examples

    # Default: stream every event for the key (no filter, no projection)
    lark-cli event consume im.message.receive_v1 --as bot
    
    # Grab one sample event to inspect payload shape
    lark-cli event consume im.message.receive_v1 --max-events 1 --timeout 30s --as bot
    
    # Run for 10 minutes then auto-exit
    lark-cli event consume im.message.receive_v1 --timeout 10m --as bot
    
    # Consume multiple EventKeys concurrently (one shape per process, no dispatcher)
    lark-cli event consume im.message.receive_v1          --as bot > receive.ndjson &
    lark-cli event consume im.message.reaction.created_v1 --as bot > reaction.ndjson &
    wait
    
    

    Call flow

    1. lark-cli event list --json → pick a legal key
    2. lark-cli event schema <key> --json → read resolved_output_schema + jq_root_path to determine field paths
    3. lark-cli event consume <key> [--jq '<expr>'] → consume

    Subprocess contract

    Ready marker

    event consume's stderr emits a fixed line [event] ready event_key=<key>. Parent processes should block on stderr until this line appears, then start reading stdout. Do not fall back to sleep.

    stdin EOF = graceful exit

    event consume treats stdin close as a shutdown signal (wired for AI subprocess callers). Bounded runs are exempt: when --max-events or --timeout is set (> 0), stdin EOF is ignored and the run exits only via its own bound, timeout, or SIGTERM. For unbounded runs, < /dev/null / nohup / systemd's default StandardInput=null will cause an immediate graceful exit (stderr reason: signal). To keep an unbounded run alive:

    • Feed stdin a source that never EOFs: < <(tail -f /dev/null)
    • Or run bounded: --max-events N / --timeout D

    Exit codes & reason

    On exit, the last stderr line is [event] exited — received N event(s) in Xs (reason: ...).

    exit codereasonTrigger
    0reason: limit--max-events reached
    0reason: timeout--timeout reached
    0reason: signalCtrl+C / SIGTERM / stdin EOF (stdin EOF applies to unbounded runs only)
    1JSON error envelope on stderrLark API business failure during pre-consume setup (for example subscription create/delete)
    2JSON error envelope on stderr (no exited line)Validation failure (unknown EventKey, bad --param / --jq, another bus already connected)
    3JSON error envelope on stderrAuth failure (missing token, missing scopes)
    4 / 5JSON error envelope on stderrNetwork / internal failure (bus startup, handshake, file I/O)

    Startup and runtime failures emit a structured JSON envelope on stderr: {"ok":false,"error":{"type","subtype","param","message","hint",...}} (the envelope may also carry top-level identity / _notice siblings). Parse error.type / error.subtype to branch (e.g. missing_scope carries a missing_scopes list), error.param to find the offending flag, and error.hint for the recovery action — do not regex-match message text.

    Orchestrators should treat reason: limit/timeout/signal (all exit 0) as "business completion" and non-zero as "failure".

    Never kill -9

    Avoid kill -9 on consume processes: for EventKeys with a PreConsume hook (those that register server-side subscriptions via OAPI), kill -9 skips the OAPI unsubscribe and leaks server-side subscriptions (symptoms: "subscription already exists" on restart, duplicate event delivery). Prefer SIGTERM or closing stdin.

    One consume, one EventKey (multi-key = multi-shell)

    The command takes exactly one positional argument; k1,k2 and wildcards are unsupported. Listening to N keys means N subprocesses — this is intentional:

    • One shape per process stdout; no dispatcher logic required in the AI
    • Fault isolation (one key failing doesn't affect others)
    • Independent --as / --jq / --max-events / --timeout per key

    All N consumers share a single bus daemon (UDS local IPC), so the overhead is small

    Writing jq via schema

    event schema <key> --json is the source of truth for writing --jq. Four things to look at:

    (1) Where fields start — see jq_root_path

    • Value "." → fields are at the top level, write .chat_id
    • Value ".event" → fields are inside a V2 envelope, write .event.chat_id

    (2) Field list and types — see resolved_output_schema.properties.<name>

    Each field carries type / description, and some also have format. Snippet (from event schema im.message.receive_v1 --json):

    {
      "chat_id":     {"type":"string", "format":"chat_id",      "description":"Chat ID, prefixed with oc_"},
      "sender_id":   {"type":"string", "format":"open_id",      "description":"Sender open_id, prefixed with ou_"},
      "create_time": {"type":"string", "format":"timestamp_ms", "description":"Send time as ms-epoch string"}
    }
    

    (3) Field semantics — see the format tag

    Lark-defined semantic tags (not JSON Schema's standard format). Common values: open_id / chat_id / message_id / timestamp_ms / email. Purpose: distinguish "same string type, different meanings" fields so you can reverse-lookup via API or convert formats.

    (4) Decoded state — read the field's description

    event consume runs Process hooks that may pre-decode some payload fields (flattening V2 envelopes, rendering .content to plain text, etc.) — behavior differs from raw OAPI. Always read the field's description before writing jq, especially for generic field names like content / data / body / payload.

    Why it matters: blindly applying fromjson to an already-decoded text field makes jq error on every event and silently drop it — the consumer looks alive but emits nothing, with only a single WARN line buried on stderr. (This is the general behavior: any jq runtime error skips the event with a one-line WARN; the loop does not abort.)

    Don't shortcut the schema: when projecting event schema --json with jq, do not strip .description from properties — that's the field that tells you whether a field is already decoded. Dump the full property objects, not just keys.


    Aside: --param's valid parameters also live in the schema — the params section lists name / type / required / enum / default / description; section missing = this key accepts no --param.

    Topic index

    TopicReferenceCoverage
    Applicationreferences/lark-event-application.mdCatalog of Application EventKeys, including application.bot.menu_v6 for custom bot menu push events + flattened event_key / operator fields + jq recipe
    Approvalreferences/lark-event-approval.mdCatalog of 2 Approval EventKeys (approval.instance.status_changed_v4, approval.task.status_changed_v4) + optional/multi subscription_type pre-registration + user-auth subscription lifecycle + flat output field reference
    IMreferences/lark-event-im.mdCatalog of 12 IM EventKeys + shape notes (flat vs V2 envelope) + im.message.receive_v1 field gotchas (sender_id is open_id only; .content is plain text except for interactive cards) + common jq recipes (filter by chat_type / message_type / sender); for card.action.trigger see also ../lark-im/references/lark-im-card-action-reply.md
    Taskreferences/lark-event-task.mdCatalog of 1 Task EventKey (task.task.update_user_access_v2) + Native V2 envelope shape + task commit types + user/bot subscription notes
    VCreferences/lark-event-vc.mdCatalog of 4 VC EventKeys (vc.meeting.participant_meeting_started_v1, vc.meeting.participant_meeting_joined_v1, vc.meeting.participant_meeting_ended_v1, vc.note.generated_v1) + field reference + source type semantics (meeting only)
    Minutesreferences/lark-event-minutes.mdCatalog of 1 Minutes EventKey (minutes.minute.generated_v1) + field reference + source type semantics (meeting only)
    Whiteboardreferences/lark-event-whiteboard.mdCatalog of 1 Board EventKey (board.whiteboard.updated_v1) + per-whiteboard subscription model (requires -p whiteboard_id=<token>) + payload field reference (whiteboard_id / operator_ids triple-id)