minutes-sdk 0.7.0 → 0.7.3
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/README.md +191 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -4
- package/dist/reader.d.ts +22 -0
- package/dist/reader.js +55 -0
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# minutes-sdk
|
|
2
|
+
|
|
3
|
+
Conversation memory for AI agents. Query meeting transcripts, decisions, action items, and people from any AI agent or application.
|
|
4
|
+
|
|
5
|
+
The "Mem0 for human conversations." Works with [Minutes](https://github.com/silverstein/minutes) meeting files or any markdown with YAML frontmatter.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install minutes-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { listMeetings, searchMeetings, findOpenActions } from 'minutes-sdk';
|
|
17
|
+
|
|
18
|
+
// List recent meetings
|
|
19
|
+
const meetings = await listMeetings('~/meetings');
|
|
20
|
+
// → [{ frontmatter: { title, date, action_items, decisions, ... }, body, path }]
|
|
21
|
+
|
|
22
|
+
// Search across all meetings
|
|
23
|
+
const results = await searchMeetings('~/meetings', 'pricing strategy');
|
|
24
|
+
|
|
25
|
+
// Find open action items
|
|
26
|
+
const actions = await findOpenActions('~/meetings', 'alex');
|
|
27
|
+
// → [{ path: '...', item: { assignee: 'alex', task: '...', status: 'open' } }]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## API
|
|
31
|
+
|
|
32
|
+
### `listMeetings(dir, limit?)`
|
|
33
|
+
|
|
34
|
+
List meetings sorted by date (newest first).
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const meetings = await listMeetings('~/meetings', 50);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `searchMeetings(dir, query, limit?)`
|
|
41
|
+
|
|
42
|
+
Full-text search across titles and transcripts.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const results = await searchMeetings('~/meetings', 'Q2 roadmap');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `getMeeting(path)`
|
|
49
|
+
|
|
50
|
+
Read a single meeting file.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const meeting = await getMeeting('~/meetings/2026-03-24-planning.md');
|
|
54
|
+
console.log(meeting.frontmatter.decisions);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### `findOpenActions(dir, assignee?)`
|
|
58
|
+
|
|
59
|
+
Find open action items, optionally filtered by assignee.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const allOpen = await findOpenActions('~/meetings');
|
|
63
|
+
const mine = await findOpenActions('~/meetings', 'mat');
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `getPersonProfile(dir, name)`
|
|
67
|
+
|
|
68
|
+
Build a profile for someone across all meetings — their meetings, open action items, and topics.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const profile = await getPersonProfile('~/meetings', 'alex');
|
|
72
|
+
// → { name, meetings: [...], openActions: [...], topics: ['pricing', 'api'] }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `parseFrontmatter(content, path)`
|
|
76
|
+
|
|
77
|
+
Parse a markdown string into a `MeetingFile`. Useful for custom integrations.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { parseFrontmatter } from 'minutes-sdk';
|
|
81
|
+
|
|
82
|
+
const meeting = parseFrontmatter(markdownString, '/path/to/file.md');
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Use with AI frameworks
|
|
86
|
+
|
|
87
|
+
### Vercel AI SDK tool
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { tool } from 'ai';
|
|
91
|
+
import { z } from 'zod';
|
|
92
|
+
import { searchMeetings } from 'minutes-sdk';
|
|
93
|
+
|
|
94
|
+
const meetingSearch = tool({
|
|
95
|
+
description: 'Search past meeting transcripts and decisions',
|
|
96
|
+
parameters: z.object({ query: z.string() }),
|
|
97
|
+
execute: async ({ query }) => {
|
|
98
|
+
const results = await searchMeetings('~/meetings', query, 5);
|
|
99
|
+
return results.map(m => ({
|
|
100
|
+
title: m.frontmatter.title,
|
|
101
|
+
date: m.frontmatter.date,
|
|
102
|
+
decisions: m.frontmatter.decisions,
|
|
103
|
+
actions: m.frontmatter.action_items,
|
|
104
|
+
}));
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### LangChain tool
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { DynamicTool } from '@langchain/core/tools';
|
|
113
|
+
import { searchMeetings } from 'minutes-sdk';
|
|
114
|
+
|
|
115
|
+
const meetingTool = new DynamicTool({
|
|
116
|
+
name: 'search_meetings',
|
|
117
|
+
description: 'Search meeting transcripts for decisions and context',
|
|
118
|
+
func: async (query) => {
|
|
119
|
+
const results = await searchMeetings('~/meetings', query, 5);
|
|
120
|
+
return JSON.stringify(results.map(m => ({
|
|
121
|
+
title: m.frontmatter.title,
|
|
122
|
+
date: m.frontmatter.date,
|
|
123
|
+
summary: m.body.slice(0, 500),
|
|
124
|
+
})));
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Types
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
interface MeetingFile {
|
|
133
|
+
frontmatter: Frontmatter;
|
|
134
|
+
body: string; // Full markdown body (transcript, summary, notes)
|
|
135
|
+
path: string; // Absolute file path
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface Frontmatter {
|
|
139
|
+
title: string;
|
|
140
|
+
type: string; // "meeting" | "memo" | "dictation"
|
|
141
|
+
date: string; // ISO 8601
|
|
142
|
+
duration: string;
|
|
143
|
+
source?: string; // "voice-memos" | "dictation" | undefined
|
|
144
|
+
device?: string; // "iPhone" etc (cross-device pipeline)
|
|
145
|
+
tags: string[];
|
|
146
|
+
attendees: string[];
|
|
147
|
+
people: string[];
|
|
148
|
+
action_items: ActionItem[];
|
|
149
|
+
decisions: Decision[];
|
|
150
|
+
intents: Intent[]; // Structured commitments, questions, decisions
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface ActionItem {
|
|
154
|
+
assignee: string;
|
|
155
|
+
task: string;
|
|
156
|
+
due?: string;
|
|
157
|
+
status: string; // "open" | "done"
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface Decision {
|
|
161
|
+
text: string;
|
|
162
|
+
topic?: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface Intent {
|
|
166
|
+
kind: string; // "commitment" | "decision" | "open-question"
|
|
167
|
+
what: string;
|
|
168
|
+
who?: string;
|
|
169
|
+
status: string;
|
|
170
|
+
by_date?: string;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## How it works
|
|
175
|
+
|
|
176
|
+
The SDK reads markdown files with YAML frontmatter produced by [Minutes](https://github.com/silverstein/minutes). No database, no server, no API key — just files on disk.
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
~/meetings/
|
|
180
|
+
├── 2026-03-24-q2-planning.md ← meetings
|
|
181
|
+
├── 2026-03-24-client-call.md
|
|
182
|
+
└── memos/
|
|
183
|
+
├── 2026-03-24-pricing-idea.md ← voice memos
|
|
184
|
+
└── 2026-03-23-onboarding-thought.md
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Each file has structured YAML frontmatter (title, date, attendees, action items, decisions, intents) and a markdown body (transcript, summary, notes). The SDK parses these and provides query functions.
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { type ActionItem, type Decision, type Intent, type Frontmatter, type MeetingFile, splitFrontmatter, parseFrontmatter, listMeetings, searchMeetings, getMeeting, findOpenActions, getPersonProfile, } from "./reader.js";
|
|
1
|
+
export { type ActionItem, type Decision, type Intent, type Frontmatter, type MeetingFile, defaultDir, splitFrontmatter, parseFrontmatter, listMeetings, searchMeetings, getMeeting, findOpenActions, findDecisions, getPersonProfile, listVoiceMemos, } from "./reader.js";
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
// decisions, action items, and people from any AI agent or app.
|
|
5
5
|
//
|
|
6
6
|
// Usage:
|
|
7
|
-
// import { listMeetings, searchMeetings } from 'minutes-sdk';
|
|
7
|
+
// import { listMeetings, searchMeetings, defaultDir } from 'minutes-sdk';
|
|
8
8
|
//
|
|
9
|
-
// const meetings = await listMeetings(
|
|
10
|
-
// const results = await searchMeetings(
|
|
9
|
+
// const meetings = await listMeetings(defaultDir());
|
|
10
|
+
// const results = await searchMeetings(defaultDir(), 'pricing');
|
|
11
11
|
export {
|
|
12
|
+
// Config
|
|
13
|
+
defaultDir,
|
|
12
14
|
// Parsing
|
|
13
15
|
splitFrontmatter, parseFrontmatter,
|
|
14
16
|
// Query API
|
|
15
|
-
listMeetings, searchMeetings, getMeeting, findOpenActions, getPersonProfile, } from "./reader.js";
|
|
17
|
+
listMeetings, searchMeetings, getMeeting, findOpenActions, findDecisions, getPersonProfile, listVoiceMemos, } from "./reader.js";
|
package/dist/reader.d.ts
CHANGED
|
@@ -84,3 +84,25 @@ export declare function getPersonProfile(dir: string, name: string): Promise<{
|
|
|
84
84
|
openActions: ActionItem[];
|
|
85
85
|
topics: string[];
|
|
86
86
|
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Default meetings directory (~\/meetings).
|
|
89
|
+
* Override with MEETINGS_DIR env var or pass a custom path to any function.
|
|
90
|
+
*/
|
|
91
|
+
export declare function defaultDir(): string;
|
|
92
|
+
/**
|
|
93
|
+
* List recent voice memos (type: memo), sorted by date descending.
|
|
94
|
+
* Useful for cross-device pipeline recall — "what ideas did I capture recently?"
|
|
95
|
+
*/
|
|
96
|
+
export declare function listVoiceMemos(dir: string, options?: {
|
|
97
|
+
days?: number;
|
|
98
|
+
limit?: number;
|
|
99
|
+
}): Promise<MeetingFile[]>;
|
|
100
|
+
/**
|
|
101
|
+
* Find decisions across all meetings, optionally filtered by topic keyword.
|
|
102
|
+
*/
|
|
103
|
+
export declare function findDecisions(dir: string, topic?: string, limit?: number): Promise<Array<{
|
|
104
|
+
path: string;
|
|
105
|
+
title: string;
|
|
106
|
+
date: string;
|
|
107
|
+
decision: Decision;
|
|
108
|
+
}>>;
|
package/dist/reader.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// listMeetings() searchMeetings()
|
|
14
14
|
import { readFile, readdir } from "fs/promises";
|
|
15
15
|
import { join, extname } from "path";
|
|
16
|
+
import { homedir } from "os";
|
|
16
17
|
import { parse as parseYaml } from "yaml";
|
|
17
18
|
// ── Parsing ──────────────────────────────────────────────────
|
|
18
19
|
/**
|
|
@@ -246,3 +247,57 @@ export async function getPersonProfile(dir, name) {
|
|
|
246
247
|
topics: Array.from(topicSet),
|
|
247
248
|
};
|
|
248
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Default meetings directory (~\/meetings).
|
|
252
|
+
* Override with MEETINGS_DIR env var or pass a custom path to any function.
|
|
253
|
+
*/
|
|
254
|
+
export function defaultDir() {
|
|
255
|
+
return process.env.MEETINGS_DIR || join(homedir(), "meetings");
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* List recent voice memos (type: memo), sorted by date descending.
|
|
259
|
+
* Useful for cross-device pipeline recall — "what ideas did I capture recently?"
|
|
260
|
+
*/
|
|
261
|
+
export async function listVoiceMemos(dir, options = {}) {
|
|
262
|
+
const { days = 14, limit = 20 } = options;
|
|
263
|
+
const cutoff = new Date();
|
|
264
|
+
cutoff.setDate(cutoff.getDate() - days);
|
|
265
|
+
const meetings = await listMeetings(dir, 500);
|
|
266
|
+
const memos = meetings.filter((m) => {
|
|
267
|
+
if (m.frontmatter.type !== "memo")
|
|
268
|
+
return false;
|
|
269
|
+
const date = new Date(m.frontmatter.date);
|
|
270
|
+
return date >= cutoff;
|
|
271
|
+
});
|
|
272
|
+
return memos.slice(0, limit);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Find decisions across all meetings, optionally filtered by topic keyword.
|
|
276
|
+
*/
|
|
277
|
+
export async function findDecisions(dir, topic, limit = 50) {
|
|
278
|
+
const files = await findMarkdownFiles(dir);
|
|
279
|
+
const results = [];
|
|
280
|
+
for (const file of files) {
|
|
281
|
+
const meeting = await readMeetingFile(file);
|
|
282
|
+
if (!meeting)
|
|
283
|
+
continue;
|
|
284
|
+
for (const decision of meeting.frontmatter.decisions) {
|
|
285
|
+
if (topic) {
|
|
286
|
+
const topicLower = topic.toLowerCase();
|
|
287
|
+
const matches = decision.text.toLowerCase().includes(topicLower) ||
|
|
288
|
+
(decision.topic && decision.topic.toLowerCase().includes(topicLower));
|
|
289
|
+
if (!matches)
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
results.push({
|
|
293
|
+
path: meeting.path,
|
|
294
|
+
title: meeting.frontmatter.title,
|
|
295
|
+
date: meeting.frontmatter.date,
|
|
296
|
+
decision,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return results
|
|
301
|
+
.sort((a, b) => b.date.localeCompare(a.date))
|
|
302
|
+
.slice(0, limit);
|
|
303
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minutes-sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Conversation memory SDK — query meeting transcripts, decisions, and action items from any AI agent or application",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist/"
|
|
9
|
+
"dist/",
|
|
10
|
+
"README.md"
|
|
10
11
|
],
|
|
11
12
|
"keywords": [
|
|
12
13
|
"meeting",
|