agentsclimarketplace

Integrate hookmyapp

Skill hookmyapp/agent-skills/skills/integrate-hookmyapp

Agent skills for WhatsApp integration with HookMyApp. Install: npx skills add hookmyapp/agent-skills

Install
npx -y skills add hookmyapp/agent-skills --skill integrate-hookmyapp

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when the user wants to integrate WhatsApp Cloud API / Meta webhooks into their app via HookMyApp, send WhatsApp or Instagram messages, publish Instagram posts, reels, or stories, read Instagram insights, manage WhatsApp templates/media or the business profile, moderate Instagram comments or receive comment webhooks, set up a sandbox session, connect WhatsApp via Meta Embedded Signup or Instagram via Instagram OAuth, connect the HookMyApp MCP server to an agent, call the HookMyApp REST API from their backend (customers, onboarding links, webhooks), or debug HookMyApp CLI errors. Triggers: hookmyapp, whatsapp cloud api, meta webhook, sandbox whatsapp, gethookmyapp, waba integration, instagram dm, instagram comments, instagram publish, instagram insights, instagram messaging api, meta instagram api, hookmyapp instagram, hookmyapp mcp.

The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

27.8 KB, as published. Nobody here has run it

Integrate HookMyApp

HookMyApp connects the user's own WhatsApp number and Instagram account to their code: inbound messages are forwarded to their code, and their replies go out over Meta's official API. Outbound sends route through the HookMyApp gateway (https://gateway.hookmyapp.com/meta/...): the user's app carries a minted hmat_ gateway access token, the gateway swaps it for the underlying Meta token server-side, and the path after /meta is verbatim Meta Graph API. This skill teaches AI coding agents how to drive the @gethookmyapp/cli to integrate a user's app with either a sandbox account (for dev and testing) or their own channel. WhatsApp uses Meta Embedded Signup; Instagram uses direct Instagram OAuth. The CLI owns credential issuance, tunnel lifecycle, and webhook configuration. For a single own-channel integration your code never needs to call the HookMyApp API directly; SaaS builders whose backend must manage customers at runtime use the REST API.

Direct Meta access still works. Integrations that already call https://graph.facebook.com with their own Meta token are unaffected. The gateway with a minted hmat_ access token is the recommended path for new setups: the access token is scoped to one channel and revocable.

Agent Guidance

Key Principles

  • The CLI is the source of truth. Never embed credentials inline in generated code. Run hookmyapp sandbox env --write .env or hookmyapp channels env <channel> --write (which exports the channel's current gateway hmat_ access token — only channels token --rotate mints a new one) and let the user's app read from environment variables.
  • There is no environment to select. Every command runs against the live HookMyApp service. Pass --workspace <id> only when the user has multiple workspaces and a command must hit one other than the active default.
  • Browser steps cannot be automated. login and channels connect both open browser tabs the human must complete. Do not pretend to automate them — hand the terminal back with a clear instruction. Exception: hookmyapp login --email <addr> is a browser-free login (an OTP code arrives at the human's email; they paste it back) — prefer it in agent/CI contexts. See references/auth.md.
  • Connecting a real channel? First ask WHOSE channel it is. Two distinct connect flows exist and they are not interchangeable. (a) The user's own team/product channel — their company's WhatsApp number or Instagram account — connects via hookmyapp channels connect (browser Embedded Signup / OAuth) into a team workspace. (b) An end-customer's channel — the user runs a SaaS and their customers bring their own numbers/accounts — connects via a customer workspace plus an onboarding link (customers onboarding-links create) that the end-customer opens; onboarding links can ONLY target customer workspaces, and the backend rejects a link pointed at a team workspace. When the user says "connect WhatsApp/Instagram" and the intent is not already obvious from context, ask one question before acting: "Is this your own team's channel, or a channel your customers will connect?" — then route to (a) or (b). Never mint an onboarding link for the user's own channel.
  • Sandbox is not your own channel. Sandbox is a HookMyApp-hosted test account with 5 env keys, no templates, and recipient pinned to the session phone. Your own channel is your WhatsApp number (7 env keys and template support) or Instagram account (6 env keys and no templates). Authorize it with channels connect, then export its runtime environment with channels env. The two are not interchangeable — pick one based on the user's goal before generating code.
  • MCP is optional; the CLI is never blocked. Setup installs the CLI — that is the whole requirement. The MCP server is a convenience for agents that prefer tool calls, and hookmyapp login configures it automatically for Claude Code. Because MCP tools resolve at session start, a server installed mid-session stays dormant until the next session: that is expected, not a failure. When mcp__hookmyapp__* tools are absent or the connection is unhealthy and a shell is available, do the task with the CLI and mention that a restart activates the tools — never tell the user the task cannot be done while the CLI can do it. (Shell-less agents are the one exception: without a working MCP connection they should say exactly which capability is missing.) Repair steps: references/mcp.md.
  • Your own channel has two webhook-delivery flavors: CLI tunnel OR your own URL. A connected channel can receive inbound webhooks via either (a) hookmyapp channels listen (the CLI provisions a per-channel Cloudflare tunnel — no public HTTPS URL required, designed for local dev / self-hosted agents / 24/7 hobby projects) or (b) hookmyapp channels webhook set <channel> --url https://... (your own public HTTPS endpoint, the classic deployed pattern). Pick CLI when the user is developing on localhost or running an always-on self-hosted agent (e.g. on a personal server or Raspberry Pi); pick URL when the user has a deployed backend ready to accept inbound webhooks. The two are mutually exclusive per channel — setting a URL while the CLI is listening evicts the CLI (it exits cleanly with a notice).

When to Prompt the Human

Use a > **HUMAN ACTION REQUIRED:** <action> blockquote whenever the next step is not automatable:

  • hookmyapp login — opens a browser tab for sign-in.
  • hookmyapp channels connect — opens the provider flow: WhatsApp Embedded Signup or direct Instagram OAuth.
  • hookmyapp channels listen — long-running foreground process; the human must keep the terminal open (or background it via nohup … & for 24/7 use). Test inbound webhook delivery by sending a real WhatsApp message to a WhatsApp channel or an Instagram DM to an Instagram channel.
  • Any destructive operation (webhook set, logout); confirm intent before running.
  • Rotating a leaked gateway hmat_ access token, via hookmyapp channels token <channel> --rotate (no Meta App Dashboard trip; the Meta token is untouched, and the old token dies immediately).

Safety Rules

  • Never paste channels env <channel> or hookmyapp channels token <channel> output (the hmat_ access token) into chat, tickets, or logs. Redirect to a secret manager or .env file the user controls.
  • Never run workspace use without confirming the target ID. Running commands against the wrong workspace can mutate the wrong WABA.
  • Never run webhook set without explicit human confirmation of the URL. Pointing your channel's webhooks at a dev URL silently drops inbound customer messages.
  • Never generate sandbox template-message examples. Templates are rejected in the sandbox; generating such code only wastes the user's time.
  • Never run hookmyapp channels disable <channel> without explicit human confirmation. Forwarding off = silent message drop on inbound; no error surfaces to the customer. Use channels show <channel> or channels health <channel> to verify state before and after.
  • Never run hookmyapp channels listen without explicit human confirmation. Listening on a real channel routes inbound customer messages to the developer's localhost. That is the intended behavior for local dev and self-hosted agents, but a misclicked channel hijacks live traffic for as long as the CLI is up. Confirm the channel publicId before launching.

Prerequisites

  • Node.js 20 or newer (for the CLI and the typical webhook server).
  • A HookMyApp account. Sign up at https://app.hookmyapp.com/signup.
  • To connect WhatsApp: a Facebook Business Manager account for Embedded Signup.
  • To connect Instagram: an Instagram professional account (Business or Creator) for direct Instagram OAuth.

Skill Setup (run before any CLI command)

Before invoking any hookmyapp CLI command, make sure the CLI exists on the user's machine:

# This skill version needs CLI >=0.14.3 <1 (instagram publish/insights/comments
# subcommands). The bounded range keeps installs on the reviewed 0.x line; an
# older existing install is upgraded in place.
command -v hookmyapp >/dev/null 2>&1 || npm install -g '@gethookmyapp/cli@>=0.14.3 <1'
# cli_ok: version is non-empty AND within >=0.14.3 <1 (a failed/missing
# `hookmyapp --version` yields an empty string and fails the check).
cli_ok() { v="$(hookmyapp --version 2>/dev/null)" || return 1; [ -n "$v" ] && printf '%s' "$v" | awk -F. '{ exit (NF == 3 && $1 == 0 && ($2 > 14 || ($2 == 14 && $3 >= 3))) ? 0 : 1 }'; }
cli_ok || npm install -g '@gethookmyapp/cli@>=0.14.3 <1'
# Re-check after the upgrade and STOP if the range still is not met — do not
# write the skill marker or continue with a CLI that lacks the new subcommands.
cli_ok || { echo "hookmyapp >=0.14.3 <1 required for this skill; install it manually and re-run." >&2; false; }

If that final check fails, stop and ask the user to upgrade the CLI themselves — do not continue to the skill-version marker below.

If npm is missing, stop and ask the user to install Node.js 20+ (which includes npm). If global installs are blocked, stop and ask the user to install the CLI themselves (npm install -g @gethookmyapp/cli) or make hookmyapp available on PATH another way — do not retry the blocked command. Do not continue with guessed commands or raw API calls just because the CLI is absent.

Then write the skill version marker so the CLI can advertise which skill is driving it. The CLI sends this version on every backend request, and the backend uses it to gate compatibility — without the marker, the skill-version check is skipped and the user can drift onto an out-of-date skill silently.

mkdir -p ~/.config/hookmyapp && echo "0.9.2" > ~/.config/hookmyapp/skill-version

The version string MUST match this skill's metadata.version in the frontmatter above. If you re-run npx skills add hookmyapp/agent-skills@latest, re-run the command above with the new version. The file is one-line UTF-8 text, no JSON, no comments — exactly a semver string. Re-running with the same value is a safe no-op.

Two paths: sandbox vs your own channel

AspectWhatsApp sandboxInstagram sandboxOwn WhatsAppOwn Instagram
AccountHookMyApp-hosted test numberHookMyApp-hosted test accountYour WABA and numberYour professional account
Setupsandbox start whatsappsandbox start instagramchannels connect whatsappchannels connect instagram
Env keys6: WEBHOOK_HMAC_SECRET, VERIFY_TOKEN, PORT, WHATSAPP_API_URL, WHATSAPP_ACCESS_TOKEN, WHATSAPP_PHONE_NUMBER_ID6: WEBHOOK_HMAC_SECRET, VERIFY_TOKEN, PORT, INSTAGRAM_API_URL, INSTAGRAM_ACCESS_TOKEN, INSTAGRAM_ACCOUNT_ID7: META_GRAPH_API_URL, WHATSAPP_ACCESS_TOKEN, WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_WABA_ID, HOOKMYAPP_CHANNEL_ID, VERIFY_TOKEN, WEBHOOK_HMAC_SECRET6: INSTAGRAM_GRAPH_API_URL, INSTAGRAM_ACCESS_TOKEN, INSTAGRAM_ACCOUNT_ID, HOOKMYAPP_CHANNEL_ID, VERIFY_TOKEN, WEBHOOK_HMAC_SECRET
Inboundsandbox listensandbox listenPublic HTTPS URL (webhook set) or CLI tunnel (channels listen)Public HTTPS URL (webhook set) or CLI tunnel (channels listen)
RecipientSession phone, pinned server-sideBound Instagram DM threadReplies within an active conversation; approved templates may initiate or resume messaging under Meta policyInstagram user in an active messaging window
TemplatesBlockedNot applicableApproved templates supportedNot applicable
Provider setupNoneNoneFacebook Business Manager and WABAInstagram Business or Creator account; no Facebook Login

Pick sandbox when the user is building or debugging on localhost and wants zero Meta paperwork for day-to-day iteration. Pick your own channel when the user is deploying to a real WhatsApp number or Instagram account (provider authorization is required once per channel).

Getting Started

The end-to-end walkthroughs live in references/getting-started.md:

  • Quickstart: Sandbox — install → login → starter kit → sandbox env/listen → first echoed message.
  • Full setup: your own channel — login → workspace → channels connect (WhatsApp Embedded Signup or Instagram OAuth) → channels envwebhook set → health check.
  • CLI-tunnel inboundchannels listen to pipe inbound webhooks to localhost with no public URL.

Read that file when starting a fresh integration; the sections below are the per-area reference an agent jumps to mid-task.

Command Reference

GroupPurposeFull reference
authLog in (browser, bootstrap code, or browser-free email OTP via login --email) and log out; credentials {list,revoke} manages the agent credentials login --email mints.references/auth.md
billingShow subscription status, open the app Billing page, upgrade plan (billing is pooled across your organization).references/billing.md
channelsConnect `[whatsappinstagram], list, show, enable/disable, disconnect, move <channel> <target>(to another workspace or customer),env/health, webhook {show,set,clear}, logs {list,show}, and listen [channel]` (per-channel CLI tunnel for inbound webhooks → localhost).
whatsapp (wa)Typed gateway wrappers for your own channel: messages {send,read}, templates {list,get,create,delete}, media {upload,get,download,delete}, profile {get,update}.references/whatsapp.md
instagram (ig)Typed gateway wrappers for your own channel: messages {send,read}, publish (image/reel/story/carousel), insights [--media], comments {list,get,reply,private-reply,hide,delete}.references/instagram.md
channel tokensRead and rotate the channel's gateway access token (hmat_…) via channels token [--rotate] (one active token per channel).references/access-tokens.md
configSet/get/unset persistent CLI config (e.g., telemetry crash-reporting on/off).references/config.md
customersSaaS customer workspaces: list, new, use, current, and onboarding-links {list,create} — mint connect links your end-customers open to connect their channel (no HookMyApp account needed).references/customers.md
sandboxStart a session `[whatsappinstagram], write the env file, open a tunnel, send test messages, webhook {show,set,clear}, logs`.
workspaceList, select, rename, and manage workspace members (tenancy scope).references/workspace.md

MCP server (operate HookMyApp without the CLI)

HookMyApp also ships a hosted MCP server at https://api.hookmyapp.com/mcp — 28 tools covering workspaces, customers, channels, webhooks, delivery logs, onboarding links, message sending, and Instagram publishing, insights, and comment moderation. Reach for it when the agent supports MCP but has no shell, or when the task is pure account operations and an MCP connection already exists; stay on the CLI for anything involving env files, tunnels, or starter kits (MCP does not mint hmat_ tokens or write env files).

Setup, for Claude Code, is already done: hookmyapp login runs hookmyapp mcp install --agent claude, which wires a credential helper that injects a fresh token on every request. Do not add the server by hand with claude mcp add — that writes an entry with no credential helper, and it cannot authenticate. For other clients, use an org API key (hmok_...) as Authorization: Bearer or X-API-Key. Browser sign-in (OAuth) is not currently operational; do not send users to /mcp sign-in or codex mcp login.

Client setup snippets, the full tool table, working order, safety rules, and a symptom-by-symptom repair table: references/mcp.md.

REST API (runtime automation from the user's backend)

When the user's own backend must operate HookMyApp at runtime — create a customer and mint an onboarding link when someone signs up in their product, read channel tokens, set webhook destinations, list delivery logs — generate code against the public REST API at https://api.hookmyapp.com (hmok_ org API key as Authorization: Bearer; customer-channel routes also need X-Workspace-Id: ws_...). Pick the surface by caller: CLI for a terminal, MCP for a shell-less agent, REST for code the user ships. Endpoint map, auth, the SaaS runtime flow, and safety rules: references/api.md.

Bundled scripts & assets (runtime fallback, no CLI at send time)

For environments where the hookmyapp CLI isn't installed at runtime, the skill ships thin Node scripts that call the gateway directly: scripts/wa-*.mjs (send, template, media, profile, mark-read) and scripts/ig-*.mjs (DM, mark-seen, comments). You still provision credentials once with hookmyapp channels env <channel> --write .env (the scripts need the resulting WHATSAPP_ACCESS_TOKEN/HOOKMYAPP_CHANNEL_ID/etc) — they then auto-load ./.env (override with --dotenv <path> or HOOKMYAPP_ENV_FILE) and run without the CLI. Each takes --help. Copy-paste request bodies live in assets/ (text, image, interactive, template-create, template-send, IG DM). Full annotated tables: references/whatsapp.md and references/instagram.md; the FILEMAP at the end lists every script and asset.

Global Options

Every command accepts these flags:

  • --json — emit JSON instead of formatted tables (pipe through jq).
  • --human — force human-readable output (default when stdout is a TTY).
  • --workspace <slug> — override the active workspace for this invocation. Accepts workspace name, slug, OR id (ws_XXXXXXXX).
  • --debug — print full HTTP request/response bodies and stack traces for troubleshooting.
  • --help — print usage and available flags for the command.

Sending Messages

Once env is populated, sending is a single HTTP POST to the gateway at https://gateway.hookmyapp.com/meta/v22.0 (META_GRAPH_API_URL), or to the sandbox proxy when WHATSAPP_API_URL is set. The path after /meta is verbatim Meta Graph API. The Authorization header carries a Bearer gateway hmat_ access token; the JSON body has messaging_product: "whatsapp", destination number (E.164), and type: "text" or type: "template".

Your app code does not change between sandbox and your own channel; only the env values change. Full code samples (JS with fetch, Python with httpx, template payloads) live in references/sending-messages.md. Integrations that prefer to call https://graph.facebook.com directly with their own Meta token still work; the gateway is the recommended path for new setups.

Instagram outbound uses a different body shape ({"recipient":{"id":"<IGSID>"},"message":{"text":"..."}}) against the Instagram Graph API base, not WhatsApp's messaging_product/to shape. See references/sending-messages.md for both.

Three ways to send (and manage templates, media, profile, comments)

Same gateway endpoint, pick the path that fits the context:

  1. CLI (preferred for scripting/CI/agents): typed wrappers — hookmyapp whatsapp messages send …, hookmyapp instagram comments reply …. Run any with --help.
  2. Bundled scripts (no CLI at runtime): node scripts/wa-*.mjs / ig-*.mjs. They auto-load ./.env (the one channels env --write produced — provision it once) and call the gateway directly.
  3. Raw HTTP (inside your running app): the fetch/httpx samples in references/sending-messages.md.
hookmyapp whatsapp messages send --channel +15551234567 --to +15557654321 --text "hi"   # CLI
node scripts/wa-send-message.mjs --to +15557654321 --text "hi"                            # script fallback

CLI commands resolve the channel from --channel (+phone, @handle, or ch_id) or fall back to HOOKMYAPP_CHANNEL_ID. Beyond sending, these cover templates, media, the WhatsApp business profile, and Instagram publishing, insights, and comment moderation. Copy-paste request bodies live in assets/ (e.g. --body @assets/wa-template-utility.json). Full recipes: references/whatsapp.md and references/instagram.md.

Webhook Payload Format

HookMyApp forwards Meta's webhook body verbatim. The envelope has entry[].changes[].value.messages[] for inbound messages:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "1276334778010256",
      "changes": [
        {
          "field": "messages",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": { "phone_number_id": "1080996501762047" },
            "messages": [
              {
                "from": "15551234567",
                "id": "wamid.abc123...",
                "timestamp": "1716300000",
                "type": "text",
                "text": { "body": "hello" }
              }
            ]
          }
        }
      ]
    }
  ]
}

Signature verification

HookMyApp signs every outbound webhook — in both sandbox and your own channel — with an HMAC-SHA256 signature sent as:

  • Header: X-HookMyApp-Signature-256
  • Format: sha256=<hex>
  • HMAC key: the channel's HMAC signing secretWEBHOOK_HMAC_SECRET, exported by BOTH hookmyapp channels env <channel> and hookmyapp sandbox env. Same key name in both contexts; never key it on VERIFY_TOKEN.
  • Body: JSON.stringify(parsedBody) on HookMyApp's side (deterministic in V8)

VERIFY_TOKEN is a separate value with one job: the plain-text body your endpoint returns on the webhook verify GET. Both surfaces carry it: real channels auto-generate one (override with hookmyapp channels webhook set <channel> --verify-token <token>), and sandbox env writes the session's VERIFY_TOKENsandbox webhook set runs the verify-GET handshake against it. Never use it as the HMAC key — channels created before the two were split (2026-06-24) happen to carry the same value in both, but new channels get two independent values.

Meta's own X-Hub-Signature-256 / APP_SECRET path is internal to HookMyApp — Meta's signature is verified before the payload is re-signed with the customer's WEBHOOK_HMAC_SECRET. Customers never see X-Hub-Signature-256 and do not need APP_SECRET. hookmyapp channels env <channel> does NOT emit APP_SECRET.

Verify it by recomputing the HMAC over the body bytes and comparing to the header:

import { createHmac } from 'node:crypto';

// hmacSecret = WEBHOOK_HMAC_SECRET from `channels env` or `sandbox env`
function verifySignature(body, signatureHeader, hmacSecret) {
  // body = JSON.stringify(parsedBody) with express.json(), or the raw string with
  // express.raw(). Both produce identical bytes (V8 JSON.stringify is deterministic).
  const expected = 'sha256=' + createHmac('sha256', hmacSecret).update(body).digest('hex');
  return signatureHeader === expected;
}

What you must NOT do is MIX the two — parse the body, mutate or reformat it, then hash the re-serialized version. Hash exactly the bytes you received (or a deterministic re-stringify of them).

Verification

Three commands to confirm a healthy integration before handing off to real traffic:

hookmyapp channels list                          # WABA appears with expected phone numbers
hookmyapp channels webhook show <channel>        # prints your webhook URL, "verified"
hookmyapp channels health <channel>              # status: healthy, quality: GREEN

For sandbox, the equivalent smoke is sandbox status plus sending a WhatsApp message to the sandbox number and confirming your server logs the inbound webhook.

Troubleshooting

SymptomFix
401 from the gatewayThe hmat_ access token is rotated or wrong. Re-read the current one with hookmyapp channels token <channel> (or channels env <channel> --write); if Meta still rejects, channels connect to re-link.
403 forbidden_wabaWABA was disconnected in Meta dashboard — reconnect via channels connect.
Webhook verify GET returns 404Ensure your server serves GET /webhook (default) with VERIFY_TOKEN body.
sandbox listen: tunnel closed / cloudflared errorsRe-run with hookmyapp sandbox listen --reinstall-tunnel-binary to force re-download cloudflared. Then check outbound 443 to *.trycloudflare.com is not firewalled.
channels listen exits with "destination was changed" noticeExpected — the dashboard webhook URL was set while the CLI was listening, so the URL wins (spec D3). Either re-run after clicking "Go back to HookMyAppCLI" in the dashboard, or run hookmyapp channels webhook clear <channel>, or accept the URL handoff and stop.
channels listen: NO_FORWARDING_CHANNELSThe channel exists but forwarding is disabled. Run hookmyapp channels enable <channel> first, then re-run channels listen.
channels listen: CHANNEL_MISMATCHThe positional channel doesn't match any channel in the active workspace. Run hookmyapp channels list to get the right publicId, OR omit the positional channel to use the picker.
Webhook arrives at HookMyApp but nothing in server logsRe-run hookmyapp sandbox listen --verbose or hookmyapp channels listen --verbose to stream full request/response bodies in the CLI terminal.
sandbox send rejected (recipient not session phone)Sandbox pins recipient; no destination flag exists. Use your own channel for multi-recipient.
channels connect: popup blockedAllow popups from app.hookmyapp.com or open the printed URL manually.

Full decision tree and error table: references/troubleshooting.md

<!-- FILEMAP:BEGIN -->
[integrate-hookmyapp file map]|root: .
|.:{package.json,SKILL.md}
|assets:{ig-send-dm.json,wa-send-image.json,wa-send-interactive-buttons.json,wa-send-template.json,wa-send-text.json,wa-template-utility.json}
|references:{access-tokens.md,api.md,auth.md,billing.md,channels.md,config.md,customers.md,env.md,getting-started.md,health.md,instagram.md,mcp.md,sandbox.md,sending-messages.md,troubleshooting.md,webhook.md,whatsapp.md,workspace.md}
|scripts:{ig-list-comments.mjs,ig-mark-seen.mjs,ig-reply-comment.mjs,ig-send-dm.mjs,wa-create-template.mjs,wa-list-templates.mjs,wa-mark-read.mjs,wa-send-message.mjs,wa-send-template.mjs,wa-update-profile.mjs,wa-upload-media.mjs}
|scripts/lib:{args.mjs,env.mjs,gateway.mjs,output.mjs}
<!-- FILEMAP:END -->

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.