osborn 0.9.42 → 0.9.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/meetings/SKILL.md +145 -0
- package/dist/index.js +111 -527
- package/dist/meeting-transcript-poller.d.ts +60 -0
- package/dist/meeting-transcript-poller.js +112 -0
- package/dist/recall-client.d.ts +50 -2
- package/dist/recall-client.js +54 -64
- package/package.json +2 -2
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Skill: Meetings
|
|
2
|
+
|
|
3
|
+
Silent note-taking and TODO-tracking when osborn is sitting in a live meeting,
|
|
4
|
+
and explicit on-demand transcript pulls from Recall.ai when the user asks.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
Two trigger patterns:
|
|
9
|
+
|
|
10
|
+
**1. Auto-tagged meeting transcript chunks** (every ~30s while a Recall bot is active):
|
|
11
|
+
Any user message that starts with `[MEETING — <botId>]:`. Also a `[SYSTEM] You are now in a meeting ...` injection on bot join.
|
|
12
|
+
|
|
13
|
+
**2. Explicit user request to pull / write notes** (any of these keyphrases in voice-native chat):
|
|
14
|
+
- "grab the meeting transcripts"
|
|
15
|
+
- "pull the meeting transcripts"
|
|
16
|
+
- "fetch the meeting transcripts"
|
|
17
|
+
- "what was said in the meeting"
|
|
18
|
+
- "update the meeting notes"
|
|
19
|
+
- "compile the todos"
|
|
20
|
+
- "write the todos"
|
|
21
|
+
- "summarize the meeting"
|
|
22
|
+
|
|
23
|
+
**Do NOT use this skill** for normal user voice-native messages that don't fit those patterns — those get spoken responses as usual.
|
|
24
|
+
|
|
25
|
+
## How to behave (auto-tagged chunks)
|
|
26
|
+
|
|
27
|
+
For every `[MEETING — *]:` message:
|
|
28
|
+
|
|
29
|
+
1. **Do NOT speak.** No TTS output. No conversational reply.
|
|
30
|
+
2. **Update `meeting-todos.md`** in the session workspace. Append new action items, decisions, open questions. One file, evolving.
|
|
31
|
+
3. **Optionally trigger background research silently** via Task tool.
|
|
32
|
+
4. **Don't consume voice-native attention.** The user can interrupt with a voice-native message at any time — that's the only kind that gets spoken responses.
|
|
33
|
+
|
|
34
|
+
## How to pull transcripts on demand (Bash + curl)
|
|
35
|
+
|
|
36
|
+
When the user explicitly asks (see triggers above), run these commands. Speak briefly first ("On it"), do the work, then speak the result.
|
|
37
|
+
|
|
38
|
+
### Step 1: Get the bot ID
|
|
39
|
+
|
|
40
|
+
The bot ID is in `meeting-todos.md` on the `**Bot:**` line. If `meeting-todos.md` doesn't exist (user is asking about a meeting that already ended in a prior session), ask the user for the bot ID or meeting URL.
|
|
41
|
+
|
|
42
|
+
### Step 2: Fetch the bot record
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
curl -sS \
|
|
46
|
+
-H "Authorization: Token ${RECALL_API_KEY}" \
|
|
47
|
+
"https://us-west-2.recall.ai/api/v1/bot/<BOT_ID>"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**CRITICAL**: The endpoint MUST be `us-west-2.recall.ai`, NOT the default `recall.ai` or `us-east-1.recall.ai`. The osborn account is provisioned in the us-west-2 region. Using the default endpoint returns 401 "OAuth authentication is currently not supported" or region-mismatch errors.
|
|
51
|
+
|
|
52
|
+
`${RECALL_API_KEY}` is preset in the agent's env — pass it through. Do NOT echo or print the raw key value in your response.
|
|
53
|
+
|
|
54
|
+
### Step 3: Extract the transcript download URL
|
|
55
|
+
|
|
56
|
+
Parse the JSON response. The transcript's pre-signed S3 URL lives at:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
recordings[0].media_shortcuts.transcript.data.download_url
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Pipe through `jq` if needed:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
DOWNLOAD_URL=$(curl -sS \
|
|
66
|
+
-H "Authorization: Token ${RECALL_API_KEY}" \
|
|
67
|
+
"https://us-west-2.recall.ai/api/v1/bot/<BOT_ID>" \
|
|
68
|
+
| jq -r '.recordings[0].media_shortcuts.transcript.data.download_url')
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If `recordings[0]` doesn't exist yet, the meeting hasn't been processed — return "the recording isn't ready yet, give it a minute" and stop.
|
|
72
|
+
|
|
73
|
+
### Step 4: Download the transcript JSON
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
curl -sS "$DOWNLOAD_URL" -o /tmp/meeting-transcript.json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The download URL is a pre-signed S3 link that **expires** (typically ~6 hours after issue). If you get a 403 or AccessDenied, re-fetch the bot record (step 2) to get a fresh URL.
|
|
80
|
+
|
|
81
|
+
### Step 5: Parse and distill into meeting-todos.md
|
|
82
|
+
|
|
83
|
+
The transcript JSON is an array of turns. Each turn has `participant.name` and `words[]` (each word has `text` + `start_timestamp.relative`). Concatenate words per turn to get the utterance.
|
|
84
|
+
|
|
85
|
+
Use `jq` to pull turns into readable lines:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
jq -r '.[] | "\(.participant.name // "Unknown"): \(.words | map(.text) | join(" "))"' /tmp/meeting-transcript.json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then update `meeting-todos.md` — distill into TODOs / Decisions / Open Questions sections. Don't paste the whole transcript verbatim into the file; summarize.
|
|
92
|
+
|
|
93
|
+
## The `meeting-todos.md` file
|
|
94
|
+
|
|
95
|
+
Path: `{session_workspace}/meeting-todos.md` — get the workspace path from spec.md or from the `[SYSTEM]` injection.
|
|
96
|
+
|
|
97
|
+
Keep it scannable. Structure:
|
|
98
|
+
|
|
99
|
+
```markdown
|
|
100
|
+
# Meeting Notes
|
|
101
|
+
|
|
102
|
+
**Bot:** <botId>
|
|
103
|
+
**Started:** <ISO timestamp>
|
|
104
|
+
**URL:** <meeting URL>
|
|
105
|
+
|
|
106
|
+
## Summary
|
|
107
|
+
<3-5 sentences distilling the meeting after it ends — added LAST>
|
|
108
|
+
|
|
109
|
+
## TODOs
|
|
110
|
+
- [ ] <person>: <action item> — <context>
|
|
111
|
+
|
|
112
|
+
## Decisions
|
|
113
|
+
- <what was decided> (raised by <person>)
|
|
114
|
+
|
|
115
|
+
## Open Questions
|
|
116
|
+
- <question> — raised by <person>, still unresolved
|
|
117
|
+
|
|
118
|
+
## Highlights
|
|
119
|
+
- <key moment or quote worth surfacing>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Update the same file across all updates — one file, evolving. Don't create `meeting-todos-1.md`, `meeting-todos-2.md`.
|
|
123
|
+
|
|
124
|
+
## On meeting end
|
|
125
|
+
|
|
126
|
+
When `[MEETING — *]:` messages stop OR the system says `[SYSTEM] meeting ended`:
|
|
127
|
+
- Pull the full final transcript (step 2-4 above)
|
|
128
|
+
- Add a `## Summary` section at the top with 3-5 lines
|
|
129
|
+
- Mark resolved open questions
|
|
130
|
+
- The next user voice-native question may be "what was the meeting about?" — answer normally (speak) from the updated file
|
|
131
|
+
|
|
132
|
+
## When the user asks about the meeting in voice-native
|
|
133
|
+
|
|
134
|
+
When a non-meeting-tagged voice message references the meeting ("what's on the todo list?", "what did we decide about X?"), respond normally — **speak** the answer. Read `meeting-todos.md` first to ground the response. If `meeting-todos.md` is empty or missing relevant detail, pull a fresh transcript first (steps 2-4) and update the file, then answer.
|
|
135
|
+
|
|
136
|
+
## Anti-patterns
|
|
137
|
+
|
|
138
|
+
- ❌ Using `recall.ai` or `us-east-1.recall.ai` — always `us-west-2.recall.ai`
|
|
139
|
+
- ❌ Using `WebFetch` for the S3 download URL — use `curl` via `Bash` (the URL has weird chars + pre-signed query strings that confuse WebFetch)
|
|
140
|
+
- ❌ Pasting the full raw transcript into `meeting-todos.md`
|
|
141
|
+
- ❌ Speaking in response to `[MEETING — *]:` messages
|
|
142
|
+
- ❌ Asking clarifying questions during a live meeting
|
|
143
|
+
- ❌ Creating a new file per pull instead of updating one
|
|
144
|
+
- ❌ Re-pulling the bot record over and over inside one user turn — fetch once, parse once
|
|
145
|
+
- ❌ Echoing or printing `${RECALL_API_KEY}` value in your response
|