vexa
Send bots to Zoom, Google Meet, and Microsoft Teams meetings. Get live transcripts, recordings, and reports. Works with Vexa Cloud or your own self-hosted instance.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-vexa
Repository
Skill path: skills/dmitriyg228/vexa
Send bots to Zoom, Google Meet, and Microsoft Teams meetings. Get live transcripts, recordings, and reports. Works with Vexa Cloud or your own self-hosted instance.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install vexa into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding vexa to shared team environments
- Use vexa for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: vexa
description: "Send bots to Zoom, Google Meet, and Microsoft Teams meetings. Get live transcripts, recordings, and reports. Works with Vexa Cloud or your own self-hosted instance."
---
## Chat-oriented interactions
Speak **directly to the user** as in a natural chat. Do not output internal reasoning, plan summaries, or procedural notes ("I need to...", "According to the skill...", "I will inform..."). Reply with only what you would say to the user — conversational, warm, and to the point.
## Plain text formatting for meeting chat
When sending messages to meeting chat (Google Meet, Teams, etc.), **always use plain text** — no markdown. These chat surfaces do not render markdown, so asterisks, hash headers, backticks, and bullet dashes appear as ugly raw characters. Use line breaks and spacing for structure instead.
Use the bundled CLI:
- `node skills/vexa/scripts/vexa.mjs ...`
- `node skills/vexa/scripts/onboard.mjs ...`
- `node skills/vexa/scripts/ingest.mjs ...`
- `node skills/vexa/scripts/audit.mjs`
## Environment
**Required:** `VEXA_API_KEY` — get yours from https://vexa.ai/dashboard/api-keys
Set `VEXA_API_KEY` in your environment or create `skills/vexa/secrets/vexa.env` manually with:
```
VEXA_API_KEY=your_key_here
```
Optional: `VEXA_BASE_URL` (env override — takes priority over endpoint config)
### Endpoint switching (prod / local dev)
The CLI supports named endpoints stored in `secrets/vexa-endpoints.json`. Default endpoints: `prod` (https://api.cloud.vexa.ai) and `local` (http://localhost:8000).
- List endpoints & active env: `node skills/vexa/scripts/vexa.mjs env:list`
- Switch to local dev: `node skills/vexa/scripts/vexa.mjs env:use local`
- Switch to prod: `node skills/vexa/scripts/vexa.mjs env:use prod`
- Add custom endpoint: `node skills/vexa/scripts/vexa.mjs env:set staging --url https://staging.vexa.ai`
- Remove endpoint: `node skills/vexa/scripts/vexa.mjs env:remove staging`
Priority: `VEXA_BASE_URL` env var > `vexa-endpoints.json` active endpoint > default prod URL.
## Secrets-first check (before any onboarding)
**Always check first:** `node skills/vexa/scripts/onboard.mjs --check-secrets`
- If output is `{"secrets_ok": true}` → secrets exist. Skip onboarding. Use normal flows.
- If output is `{"secrets_ok": false}` → run onboarding. Load `references/onboarding-flow.md`.
**Webhook — proactive setup:** Whenever secrets exist and you're working with Vexa, run `node skills/vexa/scripts/onboard.mjs --check-webhook`. If `webhook_configured` is false, advise adding the vexa mapping (see `references/webhook-setup.md`). For onboarding-only details (webhook requirements, pipeline validation, mock webhook), load `references/onboarding-flow.md`.
**When secrets are missing:** Direct the user to get their key from https://vexa.ai/dashboard/api-keys and set it up themselves. They should either set `VEXA_API_KEY` in their environment or create `skills/vexa/secrets/vexa.env` manually with `VEXA_API_KEY=their_key_here`. Do not ask users to paste API keys in chat.
**Secrets location:** `skills/vexa/secrets/` holds env files and `vexa-state.json`. This dir is gitignored. When publishing the skill to ClawHub, ensure `secrets/` is excluded.
**Per-endpoint API keys:** The CLI supports separate env files per endpoint: `vexa-prod.env`, `vexa-local.env`, etc. When switching endpoints with `env:use`, the matching `vexa-<name>.env` is loaded automatically. Falls back to `vexa.env` if no endpoint-specific file exists.
Non-interactive (for scripting): `onboard.mjs --api_key <key> --persist yes --meeting_url "<url>" --language en --wait_seconds 60 --poll_every_seconds 10`
## Quick workflows
### 1) User drops a meeting link → send bot
- After successfully sending the bot, **proactively** run `--check-webhook`. If not configured, offer to set it up so finished meetings auto-trigger reports.
- Parse/normalize link (or pass explicit ID):
- `node skills/vexa/scripts/vexa.mjs parse:meeting-url --meeting_url "https://meet.google.com/abc-defg-hij"`
- Start bot directly from URL:
- `node skills/vexa/scripts/vexa.mjs bots:start --meeting_url "https://meet.google.com/abc-defg-hij" --bot_name "Claw" --language en`
- `node skills/vexa/scripts/vexa.mjs bots:start --meeting_url "https://teams.live.com/meet/9387167464734?p=qxJanYOcdjN4d6UlGa" --bot_name "Claw" --language en`
### 2) Start bot from calendar meeting links
If a calendar tool/skill is available (for example `gog`):
1. Fetch upcoming events.
2. Extract meeting links (Google Meet/Teams).
3. For each selected event, call `bots:start --meeting_url ...`.
4. Optionally save event title into Vexa metadata:
- `meetings:update --name "<calendar title>" --notes "source: calendar"`
### 3) Read transcript during meeting or after meeting
- Poll current transcript:
- `node skills/vexa/scripts/vexa.mjs transcripts:get --platform google_meet --native_meeting_id abc-defg-hij`
- For near real-time streaming, use Vexa WebSocket API (see `references/user-api-guide-notes.md` for endpoints and notes).
- After transcript is available, summarize and store key updates.
### 4) Stop bot
- `node skills/vexa/scripts/vexa.mjs bots:stop --meeting_url "<url>"`
### 5) Create meeting report (after meeting finished)
After stopping the bot (or once the meeting has ended and transcript is finalized), create a basic meeting report:
- `node skills/vexa/scripts/vexa.mjs report --meeting_url "https://meet.google.com/abc-defg-hij"`
- or `node skills/vexa/scripts/ingest.mjs --meeting_url "<url>"`
Writes to `memory/meetings/YYYY-MM-DD-<slug>.md` with: meeting info, summary placeholders, key decisions, action items, and full transcript.
### 6) Get or update the Ultravox voice agent system prompt
The voice agent system prompt controls how the Vexa bot behaves in meetings (personality, language, what it does when triggered). It is stored per-user and applied when the next bot starts.
- Get current prompt (null = using service default):
- `node skills/vexa/scripts/vexa.mjs voice-agent:config:get`
- Set a custom prompt:
- `node skills/vexa/scripts/vexa.mjs voice-agent:config:set --prompt "You are Vexa, a concise meeting assistant..."`
- Reset to service default:
- `node skills/vexa/scripts/vexa.mjs voice-agent:config:reset`
**Note:** The updated prompt takes effect on the **next bot started** — it does not affect bots already in a meeting.
## Core commands
- Bot status:
- `node skills/vexa/scripts/vexa.mjs bots:status`
- Request bot (explicit fields):
- `node skills/vexa/scripts/vexa.mjs bots:start --platform google_meet --native_meeting_id abc-defg-hij --bot_name "Claw" --language en`
- Update active bot language:
- `node skills/vexa/scripts/vexa.mjs bots:config:update --platform google_meet --native_meeting_id abc-defg-hij --language es`
- List meetings:
- `node skills/vexa/scripts/vexa.mjs meetings:list`
- Update metadata (title/participants/languages/notes):
- `node skills/vexa/scripts/vexa.mjs meetings:update --platform google_meet --native_meeting_id abc-defg-hij --name "Weekly Product Sync" --participants "Alice,Bob" --languages "en" --notes "Action items captured"`
- Generate share URL:
- `node skills/vexa/scripts/vexa.mjs transcripts:share --platform google_meet --native_meeting_id abc-defg-hij --ttl_seconds 3600`
- Set Vexa user webhook URL:
- `node skills/vexa/scripts/vexa.mjs user:webhook:set --webhook_url https://your-public-url/hooks/vexa`
## Recordings
- List recordings:
- `node skills/vexa/scripts/vexa.mjs recordings:list [--limit 50] [--offset 0] [--meeting_id <db_id>]`
- Get a single recording:
- `node skills/vexa/scripts/vexa.mjs recordings:get <recording_id>`
- Delete a recording (destructive):
- `node skills/vexa/scripts/vexa.mjs recordings:delete <recording_id> --confirm DELETE`
- Get download URL for a media file:
- `node skills/vexa/scripts/vexa.mjs recordings:download <recording_id> <media_file_id>`
- Get recording config:
- `node skills/vexa/scripts/vexa.mjs recordings:config:get`
- Update recording config:
- `node skills/vexa/scripts/vexa.mjs recordings:config:update --enabled true --capture_modes audio,video`
## Meeting bundle (post-meeting)
Get everything about a meeting in one call — transcript, recordings, share link:
- `node skills/vexa/scripts/vexa.mjs meetings:bundle --meeting_url "https://meet.google.com/abc-defg-hij"`
- `node skills/vexa/scripts/vexa.mjs meetings:bundle --platform zoom --native_meeting_id 1234567890`
Options:
- `--segments` — include transcript segments (omitted by default to keep output small)
- `--no-share` — skip creating a share link
- `--no-recordings` — skip recordings metadata
- `--download-urls` — resolve download URLs for each recording media file
- `--ttl_seconds 3600` — share link TTL
## Webhook (meeting finished → report) — optional
Optionally, Vexa can POST a "meeting finished" webhook to trigger automatic report creation. This requires the user to manually configure their `openclaw.json` — see `references/webhook-setup.md` for the hooks mapping config. The skill does NOT modify `openclaw.json` automatically. Users who want this feature add `hooks.transformsDir` and the vexa mapping to their config themselves.
## OpenClaw ingestion helpers
- Create basic meeting report (meeting info, transcript, placeholders for summary/decisions/actions):
- `node skills/vexa/scripts/vexa.mjs report --meeting_url "<url>"`
- `node skills/vexa/scripts/ingest.mjs --meeting_url "<url>"` (or `--platform` + `--native_meeting_id`)
- Audit meetings for likely test calls / cleanup candidates:
- `node skills/vexa/scripts/audit.mjs`
## Platform rules
- Supported: `google_meet`, `teams`, `zoom`
- Teams `native_meeting_id` must be numeric ID only.
- Teams bot join requires passcode (from `?p=` in Teams URL).
- Zoom `native_meeting_id` is 10-11 digit numeric ID. Passcode (`?pwd=`) is optional.
## Deletion safety (strict)
`DELETE /meetings/{platform}/{native_meeting_id}` purges transcripts and anonymizes data.
Rules:
1. Never call delete without explicit user request for that exact meeting.
2. Verify `platform` + `native_meeting_id` first.
3. Prefer non-destructive cleanup (`meetings:update`) whenever possible.
4. Require guard flag:
- `node skills/vexa/scripts/vexa.mjs meetings:delete --platform google_meet --native_meeting_id abc-defg-hij --confirm DELETE`
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/onboarding-flow.md
```markdown
# Vexa onboarding flow
Load this file **only when** `node skills/vexa/scripts/onboard.mjs --check-secrets` returns `{"secrets_ok": false}`. If secrets exist, skip onboarding entirely.
## Important: secure key setup
- **Never** ask the user to paste API keys in chat — this is a security risk.
- **Recommended flow:** Direct the user to set `VEXA_API_KEY` in their environment, or create `skills/vexa/secrets/vexa.env` manually with content `VEXA_API_KEY=their_key_here`.
- The assistant should NOT handle raw API keys. The user sets up their own credentials.
**Chat tone:** Reply as in a natural conversation. Do not output internal reasoning or meta-commentary ("I need to ask...", "According to..."). Speak directly to the user.
## Flow (conversational)
### 1. Get API key
Direct the user to get their API key from **https://vexa.ai/dashboard/api-keys**.
### 2. Set up credentials (user does it)
Tell the user to set up their API key using one of these methods:
- Set `VEXA_API_KEY` as an environment variable in their shell
- Create `skills/vexa/secrets/vexa.env` with content `VEXA_API_KEY=their_key_here`
Then ask: **"Do you want to test it right now with a meeting? If yes, paste a Google Meet or Teams link. Quick option: create one instantly at https://meet.new"**
Use the full URL **https://meet.new** (not plain "meet.new") so it renders as a clickable link in chat.
If **no** → do step 8 (webhook), then stop.
If **yes** → ensure the shell has the key (e.g. `source skills/vexa/secrets/vexa.env`) and continue.
### 3. Create a test meeting
Ask the user to create a Google Meet or MS Teams meeting. Suggest the simplest way:
- **Google Meet:** Open **https://meet.new** in the browser — it creates a new meeting instantly. Copy the meeting URL.
- **MS Teams:** Use the Teams app to start a new meeting and copy the meeting URL.
Have the user paste the meeting URL.
### 4. Start the bot
Run:
```bash
node skills/vexa/scripts/vexa.mjs bots:start --meeting_url "<pasted_url>" --bot_name "Claw" --language en
```
Ensure `VEXA_API_KEY` is set (from env or `source skills/vexa/secrets/vexa.env`).
### 5. Test the transcript
Ask the user to **talk for a bit** (e.g. say their name and what they’re testing). Wait a short while, then fetch the transcript:
```bash
node skills/vexa/scripts/vexa.mjs transcripts:get --meeting_url "<same_url>"
```
Summarize what was transcribed so you both confirm it’s working.
### 6. Stop the bot
Always stop the bot when done. Hanging bots are bad practice:
```bash
node skills/vexa/scripts/vexa.mjs bots:stop --meeting_url "<same_url>"
```
Then do step 8 (webhook).
### 7. Key persistence
The key was saved in step 2. No further action needed.
### 8. Webhook (meeting finished → report) — **proactive**
**Always** check and offer webhook setup so that when a Vexa bot finishes a meeting, OpenClaw automatically receives the notification and creates the report. Do not wait for the user to ask.
**First check** if webhook is already configured:
```bash
node skills/vexa/scripts/onboard.mjs --check-webhook
```
- If output is `{"webhook_configured": true}` → hooks mapping exists. Still run step 9 (validate pipeline).
- If `{"webhook_configured": false}` → advise: *"You can set up the webhook so finished meetings auto-trigger reports."* Share `references/webhook-setup.md` and the exact JSON to add. The user adds it to their `openclaw.json` themselves — the skill does NOT modify this file automatically.
**If webhook config is added successfully:** Tell the user the hooks mapping is ready. **Webhook can only be set when the user has a public URL** — Vexa rejects internal URLs (localhost). Run `user:webhook:set` only if the user has a reachable public domain (e.g. cloudflared tunnel):
```bash
node skills/vexa/scripts/vexa.mjs user:webhook:set --webhook_url https://their-public-url/hooks/vexa
```
**Be explicit:** If the user has no public URL or the tunnel is not running, say: *"The webhook can't be set until you have a public URL reachable from the internet (e.g. via cloudflared). Until then, create reports manually with `vexa.mjs report`."* Point them to `references/webhook-setup.md` — section "Publishing the webhook (cloudflared tunnel)" — for steps to run the tunnel and set the Vexa URL.
### 9. Validate pipeline (after bot stopped)
**Proactively** run this to confirm the meeting finalized and a report was created:
```bash
node skills/vexa/scripts/onboard.mjs --validate-webhook --meeting_url "<same_url>"
```
This waits for the meeting to reach "completed" in Vexa (up to ~2 min), creates the report via ingest, and outputs `{"ok": true, "report_file": "..."}`. **If the real webhook was not received** (no public URL / tunnel down), it sends a **mock webhook** to the local hooks endpoint — this validates only the **local pipeline** (transform + report), not webhook delivery from Vexa. **Important (onboarding only):** Tell the user what to expect: *"Report created at [path]. The webhook needs a public URL (e.g. cloudflared) to work — until you have that, I'll create reports manually when you ask."* This sets expectations so the user knows why auto-reports may not fire.
```
### references/webhook-setup.md
```markdown
# Vexa webhook setup (meeting finished → report) — optional, user-initiated
Optionally, when a meeting finishes, Vexa can POST to your OpenClaw hooks endpoint. The bundled transform processes the webhook and triggers creation of a basic meeting report.
**This setup is entirely optional.** Without it, you can create reports manually with `vexa.mjs report`. The skill never modifies `openclaw.json` automatically — all changes below are done by you.
## Setup (manual)
1. **Set Vexa webhook URL** (points to your public OpenClaw hooks endpoint):
`node skills/vexa/scripts/vexa.mjs user:webhook:set --webhook_url https://your-domain/hooks/vexa`
2. **Add hooks mapping** in your `openclaw.json` (under `hooks.mappings`) — you edit this file yourself:
```json
{
"id": "vexa",
"match": { "path": "vexa" },
"action": "agent",
"wakeMode": "now",
"name": "Vexa meeting report",
"transform": {
"module": "skills/vexa/scripts/vexa-transform.mjs"
}
}
```
3. **Set transformsDir** to your workspace root so the transform path resolves:
```json
"hooks": {
"transformsDir": "/path/to/your/workspace",
"mappings": [ ... ]
}
```
## Behavior
- The transform runs when a webhook is received at `POST /hooks/vexa`.
- It processes only "meeting finished" events (skips in-progress, heartbeats).
- On meeting finished: injects a message instructing the agent to run `vexa.mjs report` and enrich the output (summary, entities).
- The transform lives inside the skill (`scripts/vexa-transform.mjs`) so it packs with the skill for ClawHub.
## Webhook requires a public domain
The webhook **cannot be set** without a public URL — Vexa rejects internal URLs (e.g. localhost). The webhook **cannot be validated** end-to-end without a reachable public domain; Vexa must POST to it. If there is no public URL or the tunnel (e.g. cloudflared) is not running, **Claw should be explicit**: *"The webhook can't be set until you have a public URL reachable from the internet. Until then, create reports manually with `vexa.mjs report`."*
## Publishing the webhook (cloudflared tunnel)
To make the webhook reachable, run a cloudflared tunnel pointing at the OpenClaw gateway (port 18789):
1. **Ensure OpenClaw gateway is running** (it serves hooks on 127.0.0.1:18789).
2. **Ensure cloudflared credentials exist** at `~/.cloudflared/<tunnel-id>.json`. If not:
- `cloudflared tunnel login`
- `cloudflared tunnel create openclaw-hooks` (or use an existing tunnel)
3. **Run the tunnel** (from workspace root):
```bash
cloudflared tunnel --config cloudflared-config.yml run
```
Config example (`cloudflared-config.yml`):
```yaml
tunnel: <your-tunnel-id>
credentials-file: ~/.cloudflared/<tunnel-id>.json
ingress:
- hostname: openclaw-hooks.vexa.ai
service: http://127.0.0.1:18789
- service: http_status:404
```
4. **Ensure DNS**: In Cloudflare, add a CNAME for `openclaw-hooks.vexa.ai` → `<tunnel-id>.cfargotunnel.com`.
5. **Set the Vexa webhook URL** (public hostname from your tunnel):
```bash
node skills/vexa/scripts/vexa.mjs user:webhook:set --webhook_url https://openclaw-hooks.vexa.ai/hooks/vexa
```
## Mock webhook for local pipeline only
During `--validate-webhook`, if the real webhook was not received (no public URL / tunnel down), the script sends a **mock webhook** to `http://127.0.0.1:<gateway.port>/hooks/vexa`. This validates only the **local pipeline** (transform → report), **not** webhook delivery from Vexa. Use `--send-mock-webhook` standalone to trigger this manually.
```
### references/user-api-guide-notes.md
```markdown
# Vexa API reference notes (repo research)
Primary docs reviewed:
- `docs/user_api_guide.md`
- `docs/websocket.md`
- `README.md`
## Auth + base URL
- Header: `X-API-Key: <key>`
- Hosted base URL: `https://api.cloud.vexa.ai`
- Self-hosted base URL: your Vexa deployment URL
## REST endpoints used by this skill
- `POST /bots` — request bot (`platform`, `native_meeting_id`, optional `language`, `bot_name`; Teams also needs `passcode`)
- `GET /bots/status` — list running bots
- `PUT /bots/{platform}/{native_meeting_id}/config` — update active bot config (e.g., language)
- `DELETE /bots/{platform}/{native_meeting_id}` — stop bot
- `GET /transcripts/{platform}/{native_meeting_id}` — transcript (during or after meeting)
- `POST /transcripts/{platform}/{native_meeting_id}/share` — temporary share URL
- `GET /meetings` — meeting history
- `PATCH /meetings/{platform}/{native_meeting_id}` — update metadata (`data.name`, `data.participants`, `data.languages`, `data.notes`)
- `DELETE /meetings/{platform}/{native_meeting_id}` — purge transcript + anonymize finalized meeting only
- `PUT /user/webhook` — set user webhook URL
- `GET /voice-agent-config` — get user's voice agent config (incl. custom `ultravox_system_prompt`)
- `PUT /voice-agent-config` — update voice agent config; set `ultravox_system_prompt` to a string to override, or `null` to reset to service default
## Meeting ID normalization
- Google Meet: code like `abc-defg-hij`
- Teams: numeric meeting ID from `/meet/<id>` and passcode from `?p=...`
## Real-time transcripts
- For low-latency updates, connect to `/ws` with the same API key header.
- Subscribe payload:
- `{ "action": "subscribe", "meetings": [{ "platform": "google_meet", "native_id": "abc-defg-hij" }] }`
- Main stream event to process: `transcript.mutable`
- Recommended flow from docs:
1. Bootstrap from REST transcript endpoint.
2. Merge WebSocket segments by `absolute_start_time`.
3. Prefer latest `updated_at` when segment versions conflict.
## Safety
- Treat `DELETE /meetings/...` as destructive.
- Require explicit user confirmation for exact meeting identity.
- If delete returns `409`, the meeting is not finalized yet.
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### _meta.json
```json
{
"owner": "dmitriyg228",
"slug": "vexa",
"displayName": "Skill Vexa",
"latest": {
"version": "0.1.3",
"publishedAt": 1772739378725,
"commit": "https://github.com/openclaw/skills/commit/81f36a6bdc033019e5bcd81b163f5b3aef64a615"
},
"history": [
{
"version": "0.0.1",
"publishedAt": 1770507651956,
"commit": "https://github.com/openclaw/skills/commit/195da40f29e3f97c99217bd8b671e3725d51cf45"
}
]
}
```