关于 screenpipe-api
Screenpipe 本地 REST API 的使用指南,面向需要检索屏幕、音频和活动记录的 Agent 或脚本,涵盖搜索、活动摘要、标签、同步设备查询及响应大小控制。
主要功能
- 01搜索屏幕、音频和解析数据
- 02汇总时间范围内的活动
- 03用标签关联捕获记录与记忆
- 04查询同步设备
- 05通过格式和字段缩减响应
适用场景
- 01查找指定时间段的屏幕或音频记录
- 02回顾不同应用和窗口的活动
- 03检索与人物或项目相关的记录
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ screenpipe/ screenpipe --skill screenpipe-api安装后在 Claude Code 中输入/screenpipe-api确认已加载。
详细介绍
Screenpipe API
位于 http://localhost:3030 的本地 REST API。完整参考(60+ 个端点):https://docs.screenpi.pe/llms-full.txt
身份验证
所有请求都需要身份验证。 在每次 curl 调用中添加身份验证标头:
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
-H "X-Screenpipe-Client: api" \
-H "X-Screenpipe-Agent: unknown" \
"http://localhost:3030/..."
固定值 X-Screenpipe-Client: api 用于将成功且非空的外部检索归因于 API 层。切勿在此标头中填写 Agent 名称、客户名称、项目、提示词或其他动态值。
对 REST 检索请求,请同时包含上述两个归因标头。安装程序会将 X-Screenpipe-Agent 设置为固定的应用标识符;请保留该值。如果这是尚未配置的参考值,请保留为 unknown。切勿替换为项目、用户、模型、提示词或其他动态标识符。
环境中已设置 $SCREENPIPE_LOCAL_API_KEY 环境变量。未设置该变量会收到 403。唯一的例外是 /health(无需身份验证)。
上下文窗口保护
API 响应可能很大。始终先将 curl 输出写入文件(curl ... -o /tmp/sp_result.json),检查大小(wc -c /tmp/sp_result.json);如果超过 5KB,则只读取前 50-100 行。使用 jq 提取所需内容。切勿将完整的大型响应倾倒到上下文中。
对于列表端点(/search、/elements、/frames/{id}/elements),还可以在源头减少 token:添加 &format=csv(或 tsv),即可获取按列排列的表格,每个列名只写一次,而不是每行重复键;添加 &fields=a,b,c 可仅返回所需列(支持 content.text 这类点号路径)。对于 UI 元素列表,相较于 JSON,这种方式大约可减少 70% 的 token。对于元素端点,&format=outline(别名 tree)还能进一步精简——它会生成去重、缩进的树形结构,仅包含带文本的节点(经测量,token 减少约 91%),是读取 UI 结构的最佳默认格式。规划自动化时使用 &format=automation:它会保留交互控件、状态、边界、允许的操作、响应内短引用以及尽力提取的稳定键。文本密集的 ocr/audio 几乎无法通过重新整形获益(文本块占据了绝大部分内容),因此应在这些场景中使用 fields + max_content_length。不指定 format/fields 时,响应仍为原样的 JSON。
1. 搜索 — GET /search
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
-H "X-Screenpipe-Client: api" \
-H "X-Screenpipe-Agent: unknown" \
"http://localhost:3030/search?q=QUERY&content_type=all&limit=10&start_time=1h%20ago"
参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
q | 字符串 | 否 | 关键词。音频搜索时请勿使用——转录内容噪声较多,q 会过度筛选。 |
content_type | 字符串 | 否 | all(默认)、accessibility、audio、input、ocr、memory、parsed。对于简洁的应用专属消息、电子邮件、任务、文档和代码审查,请使用 parsed。解析捕获功能尚处于实验阶段,在禁用或不受支持时可能为空,且不包含在 all 中。屏幕文本主要通过操作系统的辅助功能树(accessibility)捕获;对于不支持辅助功能的应用,OCR 是备用方案。 |
limit | 整数 | 否 | 最大值为 1-20。默认值:10 |
offset | 整数 | 否 | 分页。默认值:0 |
start_time | ISO 8601、相对时间或本地日历日期 | 是 | 可接受 2024-01-15T10:00:00Z、16h ago、today、yesterday 或 YYYY-MM-DD |
end_time | 与 start_time 相同 | 否 | 默认为 now |
app_name | 字符串 | 否 | 例如 "Google Chrome"、"Slack"、"zoom.us" |
window_name | 字符串 | 否 | 窗口标题子字符串 |
frame_id | 整数 | 否 | 当 content_type=parsed 时,返回附加到某一帧的解析数据。 |
actor_id | 整数 | 否 | 当 content_type=parsed 时,按已解析的参与者身份筛选。 |
speaker_name | 字符串 | 否 | 按说话者筛选音频(不区分大小写的部分匹配) |
focused | 布尔值 | 否 | 仅限聚焦窗口 |
tags | 字符串 | 否 | 以逗号分隔;仅返回包含所有这些标签的项目(例如 person:ada,project:atlas)。适用于屏幕/音频,以及 content_type=memory 时的记忆。请参阅下文的标签。 |
include_related | 布尔值 | 否 | 与 tags 搭配使用时,还会返回 related 映射,其中列出共同出现的标签(与你的标签同时出现的人物/项目/工作流),并按频率从高到低排列。一次调用即可获取周边上下文,无需多次调用。请参阅下文的标签。 |
max_content_length | 整数 | 否 | 截断每条结果的文本(从中间截断) |
format | 字符串 | 否 | json(默认)、csv、tsv/table 或 outline/tree(仅限元素端点)。CSV/TSV 会返回列表格式的表格(列名只写一次),而不是每行一个 JSON 对象。outline 会返回去重后的缩进文本树,其中包含带文本的 UI 节点——对于“屏幕上有什么?”这类问题,这是成本最低的读取方式(token 数约减少 91%)。CSV 不会丢失数据;TSV 会合并换行符(处理较长的 ocr 文本时效果较差)。 |
fields | 字符串 | 否 | 以逗号分隔的列白名单,使用点分隔路径,例如 type,content.app_name,content.text。仅返回这些列(便于移除重复的绝对路径 content.file_path)。json 格式也适用(返回稀疏对象)。 |
渐进式信息披露
不要直接调用开销较大的 /search。请逐步升级:
| 步骤 | 端点 | 适用场景 |
|---|---|---|
| 0 | GET /memories?q=... | 始终优先查询/并行查询——信号最强、成本最低 |
| 1 | GET /activity-summary?start_time=...&end_time=... | 宽泛的问题(“我在做什么?”、“用了哪些应用?”) |
| 2 | GET /search?... | 需要查找具体内容 |
| 3 | GET /elements?... 或 GET /frames/{id}/context | UI 结构、按钮、链接 |
| 4 | GET /frames/{frame_id} (PNG) | 需要视觉上下文 |
决策树:
- “我在做什么?” → 仅步骤 1
- “总结一下我的会议” → 步骤 2,使用
content_type=audio,不要使用 q 参数。添加content_type=all以获取屏幕上下文。 - “在 X 上花了多长时间?” → 步骤 1(
/activity-summary→ 整个时间范围的total_active_minutes,以及每个应用/窗口的minutes) - “今天用了哪些应用?” → 步骤 1(不要使用帧计数或原始 SQLite)
- “我点击了哪个按钮?” → 步骤 3(
/elements,role=AXButton) - “展示我看到的内容” → 步骤 2(查找 frame_id)→ 步骤 4
附加的活动片段
聊天消息可能包含 [Context from activity episode: ...],其中带有精确的
时间范围以及引用的屏幕、音频或会议内容。请将这些值视为检索锚点。活动标题和摘要是
生成的标签,不是捕获的内容,也不是搜索词。
- 对于有关片段详情、要点、决定或原因的问题,
请先获取底层内容再作答。从精确的时间范围开始,不带
q:通过/frames/{frame_id}/context检查引用的屏幕,使用content_type=audio查询引用的音频,使用引用的会议 ID 获取其 转录,或使用content_type=all查询混合来源的时间段。 - 切勿从活动标题或摘要中推导
q。仅当用户明确要求查找某个字面词语或短语时才使用q。 - 分析获取的内容。不要只是复述生成的摘要。
标签 — 关联人员、项目和主题
标签是在屏幕、音频和记忆之间共享的一层标签,使用统一的命名空间。请使用带命名空间的标签:person:ada、project:atlas、topic:pricing。带有相同标签的两个项目会关联起来。
- 添加到画面/音频:
POST /tags/vision/{frame_id}或POST /tags/audio/{chunk_id},请求体为{"tags":["person:ada"]}。 - 添加到记忆:在
POST /memories(或PUT /memories/{id})中包含tags。 - 按标签检索:
GET /search?tags=person:ada&start_time=30d%20ago(屏幕+音频),或添加content_type=memory来检索记忆。多个标签之间为 AND 关系;匹配为精确匹配,不是子字符串匹配。
画面会因保留策略而被清理,因此要建立持久关联,请为记忆添加标签(记忆还带有 created_at 和指向对应时刻的 frame_id,可通过 GET /frames/{frame_id} 跳转到该处)。要跨时间检索某个人的所有内容:一次调用获取捕获内容(content_type=all&tags=person:ada),另一次调用获取事实(content_type=memory&tags=person:ada)。
在标签查询中添加 include_related=true,即可在同一响应中获取周边上下文——与查询标签同时出现的标签,按命名空间分组(复数化前缀:person:→people、project:→projects),并按频率排序。用一次调用取代后续 2–3 次“还有谁/什么”的查询:
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
"http://localhost:3030/search?tags=person:ada&include_related=true&limit=5"
# data: [...], related: { "people": ["connor","drew"], "projects": ["atlas"], "workflows": ["planning"] }
关键规则
日历日期范围采用本地时间: today、yesterday 和纯 YYYY-MM-DD 日期表示用户所在时区的本地日历日,而不是 UTC 日期或滚动的 24 小时时间段。将日历字面值直接传给 API(start_time=today&end_time=now、start_time=yesterday&end_time=today)。切勿用 date -u 计算午夜,也不要附加 T00:00:00Z。
- 始终包含
start_time— 不带时间范围的查询会超时 - 从 1–2 小时的范围开始 — 仅在没有结果时扩大范围
- 用户提到特定应用时,使用
app_name - 初始时将
limit设得较低(5–10) - “recent” = 30 分钟
- 如果超时,请缩小时间范围
响应格式
{
"data": [
{"type": "OCR", "content": {"frame_id": 12345, "text": "...", "timestamp": "...", "app_name": "Chrome", "window_name": "..."}},
{"type": "Audio", "content": {"chunk_id": 678, "transcription": "...", "timestamp": "...", "speaker": {"name": "John"}}},
{"type": "UI", "content": {"id": 999, "text": "Clicked 'Submit'", "timestamp": "...", "app_name": "Safari"}},
{"type": "Parsed", "content": {"frame_id": 12345, "text": "compact corrected app data", "items": [], "actors": []}}
],
"pagination": {"limit": 10, "offset": 0, "total": 42}
}
注意:
"OCR"类型标签用于所有屏幕文本结果,包括通过辅助功能树捕获的文本。
已同步设备 — GET /data-sync/devices 和 GET /data-sync/search
当用户说另一台设备、跨设备,或提到一台并非当前设备的机器时,请使用这些端点。
仅针对当前机器时,继续使用 /search;它速度更快,且本地筛选器更丰富。
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
"http://localhost:3030/data-sync/devices"
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
"http://localhost:3030/data-sync/search?device_name=MacBook&since_hours_ago=24&q=pricing&limit=10"
设备名称不明确时,从 /data-sync/devices 开始。搜索接受
q、device_name、device_id、app_name、since、until、
since_hours_ago 和 limit。引用返回的设备和时间戳。如果 Data
Sync 已禁用或不可用,请如实说明;切勿索要云令牌、
账户 ID、用户 ID 或 R2 存储桶,也绝不要直接访问 R2。本地 API
会提供已登录的身份信息。
2. 活动摘要 — GET /activity-summary
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
-H "X-Screenpipe-Client: api" \
-H "X-Screenpipe-Agent: unknown" \
"http://localhost:3030/activity-summary?start_time=1h%20ago&end_time=now"
返回全面的概览,其中包括:
- total_active_minutes:整个时间范围内权威的总活跃屏幕使用时长(涵盖所有应用,不包括空闲间隔)。请将其用作总计/分母。切勿对
windows[].minutes求和(上限为 30),也不要打开db.sqlite重新计算时长——此字段已经是答案。 - apps:每个应用的
minutes(活跃时长)、首次/最后出现时间 - windows:每个不同窗口/标签页的标题、
browser_url及使用时长minutes——这是了解用户在做什么的最有价值字段(按时长取前 30 个) - key_texts:每个窗口上下文的一段代表性文本片段(优先显示用户输入字段,而非静态页面文本)
- audio_summary.top_transcriptions:实际转录文本,含说话者和时间戳(不只是计数)
通常只需这些信息,就足以回答“我当时在做什么?”,无需进一步搜索。只有在需要逐字引述或特定内容时,才深入查询 /search。
在构建管道/自动化流程? 规则相同:请调用此端点进行时间计算。数值由服务端根据帧时间戳计算——切勿根据原始帧重新计算时长,也不要让大模型累加分钟数(结果会产生偏差)。让模型为活动添加标签;时长则交由此端点处理。
3. 元素 — GET /elements
针对 UI 元素进行轻量级 FTS 搜索(每个元素约 100–500 字节,而 /search 返回的内容为 5–20KB)。
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/elements?q=Submit&start_time=1h%20ago&limit=10"
参数:q、frame_id、source(accessibility|ocr)、role、start_time、end_time、app_name、limit、offset,以及 format(json/csv/tsv/outline/automation)和 fields(点分隔路径)。元素都采用统一的行格式,因此精简格式在这里最能发挥优势。
format=outline(别名为 tree)是查看“屏幕上有什么?”时最省资源的读取方式——它会生成去重、缩进的文本树,仅包含带文本的节点(省略空的结构节点和边界框,将重复项折叠为 ×N,#id 是引用标识,内联显示 (disabled)/(selected)/(focused)/(expanded)/(off-screen) 状态,并限制正文长度)。最适合 source=accessibility(常见的 UI 场景——包含结构噪声、重复行、层级和状态):与 JSON 相比,可减少 85–99% 的 token(o200k_base)。扁平的 OCR 文本块压缩空间较小(约 67%,没有可去重的内容)——对于纯 OCR,format=csv&fields=text 的效果已经相当不错。
# compact outline — best default for an LLM reading the UI
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/elements?q=Submit&format=outline&limit=30"
# frame 12345 · accessibility · 8 text elements
# AXButton "Submit Order" #4012
# AXButton "Cancel" #4013 (disabled)
# AXCell "Shipped" #4020 ×6
# columnar table when you need specific columns (e.g. bounds) instead
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/elements?frame_id=12345&format=csv&fields=role,text,bounds.left,bounds.top"
GET /frames/{id}/elements?format=outline 也能以相同方式返回整个帧的树(并且有长度上限,不像原始 JSON 转储)。
format=automation 用于自动化结构,而非记忆。 它会输出
快照修订版本、简短的 ref=eN 句柄、尽力匹配的 key=k_* 标识、
键质量、状态、规范化边界框和允许的操作。每次操作前都要重新
获取。尽力匹配的键只是匹配依据,并非执行操作的授权:请验证
键、角色、名称和边界框;如果遇到 key_quality=ambiguous,请停止。
format=preferred 遵循桌面 AI 上下文设置;默认设置
会保留读取/记忆大纲。
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/frames/12345/elements?format=automation"
帧上下文 — GET /frames/{id}/context
返回某一帧的无障碍文本、解析后的节点和提取出的 URL。
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/frames/6789/context"
常见角色(因平台而异)
各平台的角色未经过标准化。请根据用户的操作系统使用正确格式:
| 概念 | macOS | Windows | Linux |
|---|---|---|---|
| 按钮 | AXButton | Button | Button |
| 静态文本 | AXStaticText | Text | Label |
| 链接 | AXLink | Hyperlink | Link |
| 文本字段 | AXTextField | Edit | Entry |
| 文本区域 | AXTextArea | Document | Text |
| 菜单项 | AXMenuItem | MenuItem | MenuItem |
| 复选框 | AXCheckBox | CheckBox | CheckBox |
| 组 | AXGroup | Group | Group |
| Web 区域 | AXWebArea | Pane | DocumentWeb |
| 标题 | AXHeading | Header | Heading |
| 标签页 | AXTab | TabItem | Tab |
| 列表项 | AXRow | ListItem | ListItem |
仅 OCR 角色(无障碍功能不可用时的回退选项):line、word、block、paragraph、page
4. 帧(屏幕截图)— GET /frames/{frame_id}
curl -o /tmp/frame.png "http://localhost:3030/frames/12345"
返回原始 PNG。每次查询最多获取 2–3 帧(每帧约 1000–2000 个 token)。
5. 媒体导出 — POST /export
渲染实时 MP4(以实际时间戳显示的屏幕帧 + 同步的麦克风音频)。片段时长与你指定的实际时间范围一致,并非加速的延时视频。
curl -X POST http://localhost:3030/export \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
-d '{"start": "5m ago", "end": "now"}'
字段:start + end(ISO 8601 或 "2h ago"、"now" 这类相对时间;end 默认为当前时间),或者使用 meeting_id 导出整场会议。可选的 output_path 会将 MP4 写入指定的绝对路径(例如 ~/Downloads/clip.mp4);否则文件会保存到数据目录的 exports/ 文件夹中。
返回 {"output_path": "...", "frame_count": N, "audio_chunk_count": N, "duration_secs": N, "file_size_bytes": N}。播放时,将 output_path 显示为行内代码块。较长的时间范围可能需要几分钟。
音频与 ffmpeg
搜索结果中的音频文件(file_path)。常见操作:
ffmpeg -y -i /path/to/audio.mp4 -q:a 2 ~/.screenpipe/exports/output.mp3 # convert
ffmpeg -y -i input.mp4 -ss 00:01:00 -to 00:05:00 -q:a 2 clip.mp3 # trim
ffmpeg -y -i input.mp4 -filter:v "setpts=0.5*PTS" -an fast.mp4 # speed 2x
ffmpeg -y -i input.mp4 -t 10 -vf "fps=10,scale=640:-1" output.gif # GIF
始终使用 -y,并保存到 ~/.screenpipe/exports/。
6. 重新转录 — POST /audio/retranscribe
curl -X POST http://localhost:3030/audio/retranscribe \
-H "Content-Type: application/json" \
-d '{"start": "1h ago", "end": "now"}'
可选项:engine(whisper-large-v3-turbo|whisper-large-v3|deepgram|qwen3-asr)、vocabulary(用于偏置/替换的 {"word": "...", "replacement": "..."} 数组)、prompt(Whisper 的主题上下文)。
时间范围应保持较短(最长 1 小时)。展示新旧转录内容。
7. 原始 SQL — POST /raw_sql
curl -X POST http://localhost:3030/raw_sql \
-H "Content-Type: application/json" \
-d '{"query": "SELECT ... LIMIT 100"}'
规则:每个 SELECT 都必须带 LIMIT。始终按时间筛选。仅限只读。时间计算请参阅下文的时间戳注意事项。
时间戳注意事项:数据库时间戳以 RFC3339 字符串形式存储,通常为 2026-06-26T18:01:14.214586+00:00(frames / audio_transcriptions / ui_events),但有些表(例如 meetings.meeting_start、memories)使用带毫秒的 Z 后缀:2026-06-26T18:01:14.214Z。不要直接将这两种格式与 SQLite 的 datetime() 字符串比较,例如 timestamp > datetime('now', '-10 seconds'):T 与空格的差异会导致按字典序比较字符串,并可能包含当天较早的过期记录。请使用 datetime(timestamp) > datetime('now', '-10 seconds')(两种格式均适用);或者在使用索引进行字符串比较时,使用符合 RFC3339 格式的截止时间:timestamp > strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now', '-10 seconds')。
警告:不要用帧数估算时间——帧由事件触发,并非按固定间隔生成。请使用 /activity-summary 查询屏幕使用时间。
架构
| 表 | 关键列 | 时间列 |
|---|---|---|
frames | app_name、window_name、browser_url、focused | timestamp |
ocr_text | text、app_name、window_name | 通过 frame_id 联结 |
elements | source、role、text、bounds_* | 通过 frame_id 联结 |
audio_transcriptions | transcription、device、speaker_id、is_input_device | timestamp |
audio_chunks | file_path | timestamp |
speakers | name、metadata | — |
ui_events | event_type、app_name、window_title、browser_url | timestamp |
accessibility | app_name、window_name、text_content、browser_url | timestamp |
meetings | meeting_app、title、attendees、detection_source | meeting_start |
memories | content、source、tags、importance | created_at |
查询示例
-- Most used apps (last 24h)
SELECT app_name, COUNT(*) as frames FROM frames
WHERE timestamp > strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now', '-24 hours') AND app_name IS NOT NULL
GROUP BY app_name ORDER BY frames DESC LIMIT 20
-- Most visited domains
SELECT CASE WHEN INSTR(SUBSTR(browser_url, INSTR(browser_url, '://') + 3), '/') > 0
THEN SUBSTR(SUBSTR(browser_url, INSTR(browser_url, '://') + 3), 1, INSTR(SUBSTR(browser_url, INSTR(browser_url, '://') + 3), '/') - 1)
ELSE SUBSTR(browser_url, INSTR(browser_url, '://') + 3) END as domain,
COUNT(*) as visits FROM frames
WHERE timestamp > strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now', '-24 hours') AND browser_url IS NOT NULL
GROUP BY domain ORDER BY visits DESC LIMIT 20
-- Speaker stats
SELECT COALESCE(NULLIF(s.name, ''), 'Unknown') as speaker, COUNT(*) as segments
FROM audio_transcriptions at LEFT JOIN speakers s ON at.speaker_id = s.id
WHERE at.timestamp > strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now', '-24 hours')
GROUP BY at.speaker_id ORDER BY segments DESC LIMIT 20
-- Context switches per hour
SELECT strftime('%H:00', timestamp) as hour, COUNT(*) as switches
FROM ui_events WHERE event_type = 'app_switch' AND timestamp > strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now', '-24 hours')
GROUP BY hour ORDER BY hour LIMIT 24
常见模式:GROUP BY date(timestamp)(按天)、GROUP BY strftime('%H:00', timestamp)(按小时)、HAVING frames > 5(过滤噪声)。
8. 连接 — GET /connections
# List all integrations (Telegram, Slack, Discord, Email, Todoist, Teams, 40+)
curl http://localhost:3030/connections
# Get connection status and non-secret settings
curl http://localhost:3030/connections/telegram
连接读取仅返回状态和已声明的非机密设置。存储的机密信息不会出现在 API 响应中。请使用专用本地端点或代理:
- Telegram:使用
{"text":"..."}调用POST /connections/telegram/send - n8n / Zapier / Make:使用任意 JSON 调用
POST /connections/<id>/proxy - Discord:使用
{"content":"..."}调用POST /connections/discord/proxy - Teams webhook:使用
{"text":"..."}调用POST /connections/teams/proxy
API 代理集成 — 凭据存储在服务端。请调用本地通配符代理;它会注入身份验证信息并转发到上游 API:
# GitHub — create an issue (repo owner/name from pipe settings)
curl -X POST http://localhost:3030/connections/github/proxy/repos/OWNER/REPO/issues \
-H "Content-Type: application/json" \
-d '{"title":"Found a bug","body":"Steps to reproduce..."}'
# GitHub — comment on an issue
curl -X POST http://localhost:3030/connections/github/proxy/repos/OWNER/REPO/issues/42/comments \
-H "Content-Type: application/json" \
-d '{"body":"Thanks for the report!"}'
# Generic OAuth proxy pattern (Zoom, Vercel, Google Docs, Microsoft 365, etc.)
curl -X POST http://localhost:3030/connections/<id>/proxy/<upstream-api-path> \
-H "Content-Type: application/json" \
-d '{...}'
不要直接从管道调用 https://api.github.com/... — 请改用 /connections/github/proxy/...。不存在 /connections/<id>/token 端点。
如果尚未连接,请告知用户在桌面应用的 Connections 页面中进行设置。
9. 会议 — GET /meetings、PUT /meetings/:id
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/meetings?start_time=1d%20ago&end_time=now&limit=10&offset=0"
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/meetings?q=alice%40acme.com"
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/meetings/42"
# Update mutable fields. This is a partial update body: omitted fields stay as-is.
curl -X PUT http://localhost:3030/meetings/42 \
-H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Q3 planning", "note":"<existing note>\n\n## Summary\n<summary>"}'
返回检测到的会议(来自日历、应用检测、窗口标题、UI 元素和多说话人音频)。q 是针对标题、参会者和备注的不区分大小写的子串筛选条件。
会议更新使用 PUT /meetings/:id,而非 PATCH。在追加 AI 生成的摘要之前,请先读取当前会议,并将现有的 note 文本包含在新备注正文中,以保留用户编写的备注。
| 字段 | 类型 | 描述 |
|---|---|---|
id | integer | 会议 ID |
meeting_start | ISO 8601 | 开始时间 |
meeting_end | ISO 8601? | 结束时间(进行中时为 null) |
meeting_app | string | 应用(zoom、teams、meet 等) |
title | string? | 会议标题 |
attendees | string? | 参会者 |
note | string? | 用户备注 / 追加的 AI 摘要 |
detection_source | string | 检测方式(app、calendar、ui 等) |
也可通过原始 SQL 查询:SELECT * FROM meetings WHERE meeting_start > strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now', '-24 hours') LIMIT 20
10. 说话人 — 管理与重新分配
# Search speakers by name
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/speakers/search?name=John"
# Get unnamed speakers (for labeling)
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/speakers/unnamed?limit=20&offset=0"
# Get speakers similar to a given speaker (by voice embedding)
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/speakers/similar?speaker_id=29&limit=5"
# Update speaker name/metadata
curl -X POST http://localhost:3030/speakers/update \
-H "Content-Type: application/json" \
-d '{"id": 29, "name": "Jordan"}'
# Reassign speaker for an audio chunk (propagates to similar chunks by default)
curl -X POST http://localhost:3030/speakers/reassign \
-H "Content-Type: application/json" \
-d '{"audio_chunk_id": 456, "new_speaker_name": "Jordan", "propagate_similar": true}'
# Returns: new_speaker_id, transcriptions_updated, old_assignments (for undo)
# Undo a speaker reassignment
curl -X POST http://localhost:3030/speakers/undo-reassign \
-H "Content-Type: application/json" \
-d '{"old_assignments": [{"transcription_id": 1, "old_speaker_id": 29}]}'
# Merge two speakers (keeps one, merges the other into it)
curl -X POST http://localhost:3030/speakers/merge \
-H "Content-Type: application/json" \
-d '{"speaker_to_keep_id": 5, "speaker_to_merge_id": 29}'
# Mark speaker as hallucination (false detection)
curl -X POST http://localhost:3030/speakers/hallucination \
-H "Content-Type: application/json" \
-d '{"speaker_id": 29}'
# Delete a speaker (also removes associated audio chunk files)
curl -X POST http://localhost:3030/speakers/delete \
-H "Content-Type: application/json" \
-d '{"id": 29}'
说话人重新分配工作流
当用户说“那其实是 Jordan,不是 Karishma”时:
- 搜索音频结果,找到被错误识别音频的
chunk_id - 调用
POST /speakers/reassign,并传入audio_chunk_id和new_speaker_name - 设置
propagate_similar: true(默认值)后,也会修正听起来相似的片段
11. 已解析的应用数据和参与者
已解析的数据使用与其他所有可读取内容类型相同的搜索界面:
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" \
"http://localhost:3030/search?content_type=parsed&start_time=2h%20ago&limit=10"
结果包含经过校正的精简 text、有类型的 items、解析器来源信息,以及单独的 actors 数组,用于可更正的身份信息。使用 frame_id 筛选单个帧,或使用 actor_id 筛选单个已解析身份。参与者编辑需明确执行:先调用 GET /semantic/actors/search,然后调用 POST /semantic/actors/create、update、merge、reassign 或 aliases/reassign。切勿仅凭显示名称合并参与者;解析器标签是观测到的证据,而参与者记录是可变的。
12. 记忆 — 高信号持久知识
记忆是 screenpipe 中信号最高的数据源。 其中包含经过整理的事实、用户偏好、决策和项目背景 — 这些内容是从数小时的屏幕 / 音频数据中提炼出来的。回答问题或构建上下文时,务必查看记忆。
何时查询记忆
在以下情况下,先查询记忆(在 /search 之前或同时):
- 用户询问偏好、决策或过去的上下文
- 需要了解项目、人物或工作流的背景
- 要生成摘要、建议或行动计划
- 不确定用户的偏好或过去的决定
- 任何能从历史上下文中受益的任务
规则:如果调用 /search,也要并行调用 /memories。 记忆能提供原始屏幕数据背后的“原因”。搜索会告诉你发生了什么;记忆会告诉你什么才重要。
API
# Search memories (FTS) — do this often!
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/memories?q=preference&limit=20"
# List recent memories (high importance first)
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/memories?min_importance=0.5&limit=20"
# Filter by source or tags
curl -H "Authorization: Bearer $SCREENPIPE_LOCAL_API_KEY" "http://localhost:3030/memories?source=user&tags=project&limit=20"
# Create a memory
curl -X POST http://localhost:3030/memories \
-H "Content-Type: application/json" \
-d '{"content": "User prefers dark mode", "source": "user", "tags": ["preference", "ui"], "importance": 0.7}'
# Update a memory
curl -X PUT http://localhost:3030/memories/1 \
-H "Content-Type: application/json" \
-d '{"content": "User prefers dark mode in all apps", "importance": 0.8}'
# Delete a memory
curl -X DELETE http://localhost:3030/memories/1
GET /memories 的参数:q(全文搜索)、source、tags、min_importance、start_time、end_time、limit、offset。
记忆也会出现在 /search?content_type=memory 中。
创建记忆
当你了解到有关用户的重要信息(偏好、决策、项目背景)时,请将其存储为记忆。使用 importance 0.0-1.0 对信息价值进行排序。只存储真正有用且长期有效的信息,不要存储短暂的观察。
12. 通知 — POST http://localhost:11435/notify
向 screenpipe 桌面 UI 发送通知。此功能使用 Tauri sidecar 服务(端口 11435),而不是主 API(端口 3030)。
通知正文支持 markdown:**粗体**、`行内代码` 和 [链接文本](url)。链接可以是网页 URL、文件路径或 screenpipe 深层链接。
将 priority 设为 high、normal(默认值)或 low。每种优先级的通知都会显示在右上角的通知面板中。只有在需要立即告知用户的时效性故障或重要决策时才使用 high;此类通知也会显示在专门的 Priority 收件箱中。normal 会保留在 All 中,而 low 默认只显示为短暂通知。完成日志和常规同步绝不能设为 high。
# Simple notification
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "3 new voice memos", "body": "found recordings from today"}'
# Markdown body with links
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "Meeting summary", "body": "**Q3 Planning** notes saved\n\nopen [meeting notes](~/Documents/notes/q3.md) or view [recording](screenpipe://timeline)"}'
# Link to a local file (absolute path or ~ path)
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "Export complete", "body": "saved to [report.csv](~/Downloads/report.csv)"}'
# With action buttons
# Use `type: "link"` for external URLs and `type: "deeplink"` for
# screenpipe:// in-app routes. `type: "dismiss"` closes the notification.
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "Meeting summary", "body": "**Q3 Planning**\n- Budget approved", "actions": [{"id": "view", "label": "view", "type": "deeplink", "url": "screenpipe://timeline"}, {"id": "skip", "label": "skip", "type": "dismiss"}]}'
# External URL action (opens in browser)
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "PR ready for review", "body": "nice work", "actions": [{"id": "open", "label": "open pr", "type": "link", "url": "https://github.com/screenpipe/screenpipe/pull/1234"}]}'
# Ask permission, then run a pipe on approval — the opt-in / agent-gated flow.
# `type: "pipe"` runs the TARGET pipe when clicked (POST /pipes/<pipe>/run); the
# `context` is injected into that pipe's prompt as the notification action
# context. Set `pipe` EXPLICITLY — if omitted it falls back to the sending pipe,
# which usually does nothing. Add `"open_in_chat": true` to run it in the chat UI
# so the user sees the output live instead of in the background.
# Actions persist into the notification bell, so the user can still approve from
# the bell after the ~20s toast fades.
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "share meeting notes with the team?", "body": "approve to send the adriaan call notes", "priority": "high", "actions": [{"id": "approve", "label": "approve", "type": "pipe", "primary": true, "pipe": "share-data", "context": {"meeting_id": 274}}, {"id": "decline", "label": "decline", "type": "dismiss"}]}'
# Run an inline prompt in a fresh chat session on click (`type: "chat"`).
# No pre-installed pipe needed — write the whole task in `prompt`, attach data
# in `context`. Add `"auto_send": false` to pre-fill chat for the user to
# review/edit before sending. This is the lightweight counterpart to a `pipe`
# action for one-off "approve → do this specific thing" flows.
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "summarize this call into a CRM note?", "body": "approve to draft it", "priority": "high", "actions": [{"id": "go", "label": "draft it", "type": "chat", "primary": true, "prompt": "summarize meeting 274 into a short CRM follow-up note and save it to output/", "context": {"meeting_id": 274}}, {"id": "no", "label": "no", "type": "dismiss"}]}'
# Call a local API endpoint on click (`type: "api"`)
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "stop recording?", "body": "tap to stop", "actions": [{"id": "stop", "label": "stop", "type": "api", "url": "/recording/stop", "method": "POST"}]}'
# Custom auto-dismiss (5 seconds)
curl -X POST http://localhost:11435/notify \
-H "Content-Type: application/json" \
-d '{"title": "Saved", "body": "Note saved", "timeout": 5000}'
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
title | string | 是 | 通知标题 |
body | string | 是 | Markdown 正文(**粗体**、`代码`、[文本](url)) |
type | string | 否 | 类别(默认值为 "pipe") |
priority | high | normal | low | 否 | 默认值为 normal;所有优先级的通知都会显示在右上角,只有 high 会进入专门的 Priority 视图 |
timeout | integer | 否 | 自动关闭时间,单位为毫秒(默认值为 20000) |
autoDismissMs | integer | 否 | timeout 的别名 |
actions | array | 否 | 操作按钮(最多 5 个;每个按钮都需要 id、label、type) |
操作按钮的 type:
link— 在浏览器中打开网页 URL(url)deeplink— 在 screenpipe 中导航(url=screenpipe://...)pipe— 点击时运行已安装的 pipe(pipe= 目标 pipe 名称,可选的context会注入其提示词,可选的open_in_chat)。用于选择加入或由 Agent 控制分享的机制。chat— 在新的聊天会话中运行内联prompt(无需安装 pipe;可选的context作为背景数据,可选的auto_send默认值为 true)。这是pipe的轻量替代方式,适用于一次性的“批准并执行”流程。api— 向本地端点发送 POST 请求(url,可选的method、body)dismiss— 关闭通知,不产生其他副作用primary: true会以填充样式显示按钮(推荐操作)。操作会保留在通知铃铛中,因此即使错过了短暂通知,仍然可以执行操作。
正文 Markdown 支持的链接类型:
- 网页 URL:
[文档](https://docs.screenpi.pe)— 在浏览器中打开 - 文件路径:
[笔记](~/notes/file.md)或[日志](/var/log/app.log)— 在默认应用中打开 - 深层链接:
[时间线](screenpipe://timeline)— 在 screenpipe 中导航
返回 {"success": true, "message": "Notification sent successfully"}。
13. 其他端点
curl http://localhost:3030/health # Health check
curl http://localhost:3030/audio/list # Audio devices
curl http://localhost:3030/vision/list # Monitors
深层链接
使用可点击链接引用特定时刻:
[10:30 AM — Chrome](screenpipe://frame/12345) # screen text results (use frame_id)
[meeting at 3pm](screenpipe://timeline?timestamp=ISO8601) # Audio results (use timestamp)
只使用实际搜索结果中的 ID/时间戳。绝不要伪造。
显示视频
将搜索结果中的 file_path 作为行内代码展示,以播放视频:
`/Users/name/.screenpipe/data/monitor_1_2024-01-15_10-30-00.mp4`