runway-characters-meeting
Send a Runway AI Character to any Zoom, Google Meet, or Microsoft Teams meeting. The character joins as a real participant — sees the room, hears everything, and responds live with lip-synced video, voice, and expressions. Use this skill whenever the user wants to send an AI character or avatar to a video call, clone themselves for a meeting, create a digital twin, or mentions a meeting link (meet.google.com, zoom.us, teams.microsoft.com) and wants an AI to join it. Also triggers for voice cloning for meetings, creating characters for calls, or getting post-call transcripts.
Skill body
Runway Characters Meeting
Script: SKILL_DIR refers to this skill’s root directory.
All commands run through a single script: $SKILL_DIR/scripts/runway_meeting.py
First-Time Setup
Run once when the skill is first loaded:
pip install -r $SKILL_DIR/requirements.txt
1. API Key
Check if RUNWAYML_API_SECRET is set. If not, stop and tell the user:
You need a Runway API key. Get one free at https://dev.runwayml.com, then set:
export RUNWAYML_API_SECRET=key_...
Do not proceed without a valid API key.
2. Character
Check if the user already has a character by running:
python $SKILL_DIR/scripts/runway_meeting.py create-character --list
If a character exists with status ✓ READY: use its ID. Skip to Join Flow.
If no characters exist: guide the user through character creation. Ask:
I need to set up a character for your meetings. You have three options:
- Clone yourself — send me a selfie and a voice recording (10s–2min), and I’ll create your digital twin
- Quick start — I’ll create a custom character with a bundled avatar and a preset voice
- Use a preset — jump into a meeting instantly with a ready-made character (no setup needed):
game-character·game-character-man·music-superstar·cat-character·influencer·tennis-coach·human-resource·fashion-designer·cooking-teacherWhich do you prefer? (or just send me a selfie to get started)
Do not proceed until the user responds. Do not auto-create.
User chooses a preset: skip character creation entirely. Use the preset ID directly in the join command:
python $SKILL_DIR/scripts/runway_meeting.py join \
--meeting-url "<MEETING_URL>" \
--avatar-type "runway-preset" \
--preset-id "<preset-id>"
No personality, voice, or face setup needed. Skip to Join Flow.
User chooses clone-yourself:
python $SKILL_DIR/scripts/runway_meeting.py clone-yourself \
--name "<user's name>" \
--selfie <path-to-selfie> \
--voice-audio <path-to-recording> \
--personality "<personality — see Personality Guidelines below>"
If the user only has a selfie but no voice recording, use --voice "luna" instead of --voice-audio.
If the user has no selfie, use --face-description "<description>" or omit for the bundled default.
User chooses quick start:
python $SKILL_DIR/scripts/runway_meeting.py create-character \
--name "<name>" \
--voice "luna" \
--personality "<personality>"
This uses a bundled default face from $SKILL_DIR/assets/. Available bundled faces:
monster.png · cat.png · warrior.png · boy.png
To use a specific one: --image "$SKILL_DIR/assets/cat.png"
Output: the command prints a character ID and saves it to ~/.runway-characters.json.
Store this ID — reuse it for every join. Do NOT create a new character each time.
3. Voice (optional, for advanced users)
If the user wants a custom voice separately (not through clone-yourself), use:
# Clone from audio recording:
python $SKILL_DIR/scripts/runway_meeting.py clone-voice \
--name "My Voice" --audio <path-to-recording>
# Or generate from text description:
python $SKILL_DIR/scripts/runway_meeting.py clone-voice \
--name "My Voice" \
--description "A warm, professional voice with a calm tone"
# Preview before creating:
python $SKILL_DIR/scripts/runway_meeting.py clone-voice \
--description "A warm, professional voice" --preview
Voice cloning requires 10s–2min of clear speech, under 10MB. Text descriptions must be at least 20 characters. Runway voices do not expire — once created, they’re available forever.
Pass the voice ID to character creation: --voice-id <VOICE_UUID>
# List existing custom voices:
python $SKILL_DIR/scripts/runway_meeting.py clone-voice --list
Join Flow
Step 1 — Validate before joining
Before every join, check these in order:
- API key:
RUNWAYML_API_SECRETmust be set - Character: confirm the character ID is valid (check
~/.runway-characters.jsonor runcreate-character --list) - Meeting URL: must be a valid Zoom, Google Meet, or Teams link
If any check fails, guide the user to fix it before proceeding.
Step 2 — Gather context
Always gather fresh context before joining — do not reuse stale context from a previous session.
- Read any available workspace files (MEMORY.md, daily logs, meeting notes, project docs)
- If no workspace data is available, ask the user:
What's this meeting about? Any names, topics, or agenda items I should know? - Synthesize a concise, meeting-specific personality override:
Synthesize the information below into a concise reference card for {name} to use
during a voice/video call. Use third-person throughout. Prioritize CONCRETE DETAILS.
PRIORITY ORDER:
1. SPECIFIC FACTS: names, places, dates, numbers, events
2. RECENT ACTIVITY: what happened today/this week — actions, not vibes
3. RELATIONSHIPS: who matters, specific interactions
4. PERSONALITY: 1-2 sentences MAX
CURATION RULES:
- KEEP: anything with a proper noun, a number, a date, or a concrete action
- DROP: vague descriptions, routine status updates, empty entries
- MERGE: if multiple entries say similar things, pick the most vivid one
OUTPUT FORMAT:
**{name}**: [1 sentence — tone/vibe]
**Known facts** (concrete only, max 10):
- [specific fact with names/dates/numbers]
**Recent activity**:
- [built X, fixed Y, went to Z]
**Right now**: [1 line — current activity]
**People**: [name — 1 specific detail each]
RULES:
- Concrete > abstract
- Actions > descriptions
- Do not invent facts
- If data is thin, keep it short — don't pad with filler
Step 3 — Join the meeting
Custom character (recommended):
python $SKILL_DIR/scripts/runway_meeting.py join \
--meeting-url "<MEETING_URL>" \
--avatar-id "<CHARACTER_UUID>" \
--personality "<context-aware personality from Step 2>"
With a meeting password (for password-protected Zoom rooms):
python $SKILL_DIR/scripts/runway_meeting.py join \
--meeting-url "<MEETING_URL>" \
--avatar-id "<CHARACTER_UUID>" \
--meeting-password "<password>"
Custom display name (defaults to the character’s name):
python $SKILL_DIR/scripts/runway_meeting.py join \
--meeting-url "<MEETING_URL>" \
--avatar-id "<CHARACTER_UUID>" \
--bot-name "Yining's AI"
Preset avatar (fallback — no character creation needed):
python $SKILL_DIR/scripts/runway_meeting.py join \
--meeting-url "<MEETING_URL>" \
--avatar-type "runway-preset" \
--preset-id "game-character"
Available preset IDs:
game-character · game-character-man · music-superstar · cat-character
influencer · tennis-coach · human-resource · fashion-designer · cooking-teacher
Exit codes:
| Code | Meaning | What to tell the user |
|---|---|---|
0 |
Joined successfully | “✓ [Name] has joined your meeting.” |
1 |
General error | Show the error message |
2 |
Insufficient credits | “You’re out of Runway credits. Add more at https://dev.runwayml.com/billing” |
3 |
Bad meeting URL | “That meeting link may have expired. Can you send a fresh one?” |
Store the returned sessionId internally — never expose session IDs to the user.
Step 4 — Confirm and offer controls
Tell the user:
✓ [Character name] has joined your [Zoom / Google Meet / Teams] call. Say “leave the meeting” when you want them to hang up.
Leave Flow
When the user says “leave”, “end the call”, “hang up”, “remove”, or similar:
python $SKILL_DIR/scripts/runway_meeting.py leave --session-id "<SESSION_ID>"
Tell the user: “✓ [Name] has left the meeting.”
Always run transcript + save-memory immediately after leaving:
python $SKILL_DIR/scripts/runway_meeting.py transcript \
--session-id "<SESSION_ID>" \
--save-memory \
--avatar-id "<CHARACTER_UUID>"
This saves the conversation to the character’s persistent memory so it remembers past meetings automatically on the next join. The last 5 meeting summaries are injected into context on every future join.
Also leave automatically if the conversation is ending and a session is still active.
Checking Session Status
python $SKILL_DIR/scripts/runway_meeting.py status --session-id "<SESSION_ID>"
Getting the Transcript
python $SKILL_DIR/scripts/runway_meeting.py transcript \
--avatar-id "<CHARACTER_UUID>" \
--session-id "<SESSION_ID>"
Returns the full conversation transcript after the call ends.
Save with a custom summary (instead of auto-building from transcript):
python $SKILL_DIR/scripts/runway_meeting.py transcript \
--session-id "<SESSION_ID>" \
--save-memory \
--avatar-id "<CHARACTER_UUID>" \
--summary "Discussed Q3 roadmap with Alex and Sam. Key decision: launch in October."
Personality Guidelines
When building the --personality for a meeting, follow these principles:
- Concrete details beat abstract instructions — include real names, real topics, real agenda items
- Include the character’s role in this specific meeting
- Keep responses short: 1–3 sentences unless asked for more
- Wait to be addressed before speaking in group calls
- Characters speak any language — just instruct them in the personality (e.g., “Respond in Spanish at all times”)
Example:
You are Aria, a helpful AI assistant joining a product review meeting.
Context: the team is reviewing the Q3 roadmap. Participants: Alex (PM), Sam (Eng).
Be concise and speak only when addressed. Keep answers under 2 sentences.
Available Voices
30 built-in preset voices (no setup needed):
| Voice | Gender | Style | Voice | Gender | Style | |
|---|---|---|---|---|---|---|
luna |
F | Warm | adrian |
M | Smooth | |
maya |
F | Upbeat | adam |
M | Friendly | |
clara |
F | Soft | leo |
M | Easy-going | |
skye |
F | Bright | felix |
M | Excitable | |
victoria |
F | Firm | max |
M | Upbeat | |
nina |
F | Smooth | zach |
M | Casual | |
emma |
F | Clear | morgan |
M | Informative | |
mia |
F | Youthful | vincent |
M | Knowledgeable | |
summer |
F | Breezy | marcus |
M | Firm | |
ruby |
F | Easy-going | jasper |
M | Clear | |
aurora |
F | Bright | david |
M | Informative | |
georgia |
F | Mature | blake |
M | Gravelly | |
petra |
F | Forward | drew |
M | Breathy | |
violet |
F | Gentle | nathan |
M | Firm | |
roman |
M | Lively | ||||
sam |
M | Even |
Or clone your own voice — see First-Time Setup above.
Persistent Memory
The character remembers past meetings and uses that context in future calls.
How it works:
- After a meeting ends, run
transcript --save-memoryto save the summary - On the next
join, the last 5 meeting summaries are automatically injected into context - The character can then reference past topics, decisions, and participants
Memory is stored locally in ~/.runway-characters.json. Each character keeps up to 10 summaries (oldest are dropped automatically).
Billing & Credits
- Cost: ~$0.20/min of active session (1 credit = 3 seconds, 1 credit = $0.01)
- Character creation is free — only active sessions cost credits
- Always leave the session when the meeting ends to stop billing
- If join fails with exit code
2, tell the user to add credits at https://dev.runwayml.com/billing
Error Recovery
| Error | Action |
|---|---|
| Invalid or expired meeting URL (exit 3) | Ask user for a fresh invite link |
| Credits exhausted (exit 2) | Direct to https://dev.runwayml.com/billing |
| Character not found | Run create-character --list and pick a valid ID |
| Server error | Retry once after 5 seconds |
| Character status PROCESSING | Wait 10–30s for READY, then retry |
Notes
- Supports Zoom, Google Meet, and Microsoft Teams
- Custom characters must have status
READYbefore joining — presets are always available --personalityonjoinoverrides the character’s stored personality for that session only- Works with any face: human selfies, animal photos, cartoon characters, abstract art
- Latency: ~1.5 seconds — feels like a real video call
- Never expose session IDs, API keys, or internal details in messages to the user