[integrations] Wearable capture core#48
Conversation
Reusable engine that turns any polling wearable (Omi, Limitless, future devices) into Open Brain thoughts. Per-device adapters implement a four-method WearableAdapter interface (sourceId, sourceType, listSince, recordId, recordToThoughts); the core owns auth, idempotent dedup (on the device's own record id, stored in thoughts.metadata — no local state file), OpenRouter embedding, and inserts into thoughts. Additive only; no thoughts-schema changes; secrets via Deno.env. Adapters: wearable-omi-capture, wearable-limitless-capture.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d225dae94b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Copy [`wearable-sync.ts`](./wearable-sync.ts) from this folder to `supabase/functions/_shared/wearable-sync.ts`. | ||
|
|
||
| ✅ **Done when:** `supabase/functions/_shared/wearable-sync.ts` exists and `deno check supabase/functions/_shared/wearable-sync.ts` is clean. |
There was a problem hiding this comment.
Include the import map in the install path
When users follow this install step in a Supabase project that does not already map @supabase/supabase-js, the copied _shared/wearable-sync.ts cannot be checked or deployed because its bare import relies on this integration folder's deno.json, which the instructions leave behind. Either use a fully qualified npm:/JSR/URL import in the shared file or document copying/adding the import map alongside it so the README's deno check supabase/functions/_shared/wearable-sync.ts condition can actually pass.
Useful? React with 👍 / 👎.
| .contains("metadata", { wearable_source: adapter.sourceId, provider_event_id: providerEventId }) | ||
| .limit(1); | ||
| if (selErr) throw selErr; | ||
| if (existing && existing.length > 0) { skipped++; continue; } |
There was a problem hiding this comment.
Preserve retries for multi-thought records
For adapters that return multiple thoughts for one provider record, the first successful insert stores this provider_event_id; if a later thought in the same loop fails during embedding or insert, the next sync sees that one existing row and skips the entire record, so the remaining thoughts are never retried. Include a per-thought sub-id/index in the idempotency key or make all thoughts for a record commit atomically before treating the provider event as captured.
Useful? React with 👍 / 👎.
Summary-per-recording capture lost the detail inside long voice recordings. Rework the core to emit ATOMS (title, action items, events, transcript chunks) using the device's own structure, so each becomes its own searchable, individually-attributed thought — still no per-item LLM cost. Replace device-id dedup with a salted per-atom fingerprint sha256(source|provider_event_id|atom_index|content), deduped via a GIN-indexed metadata containment query so it stays additive on the baseline thoughts schema. Tag every atom with attribution (self/other/mixed/machine/unknown) + attributed_to + generator, and add a Retry-After-aware fetch helper so a 429 slows a pass instead of aborting it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
A reusable engine that turns any polling wearable (Omi, Limitless, future devices) into Open Brain thoughts. Per-device adapters implement a small four-method interface; the core owns everything they share.
Why
Always-on wearables expose your spoken life through a polling API, and each needs the same plumbing to reach the brain — pull recent records, skip already-captured ones, embed, insert. This packages that once so a new device is a ~40-line adapter, not a new pipeline.
How it works
sourceId,sourceType,listSince(sinceISO),recordId(record),recordToThoughts(record).runWearableSync) — pulls a rolling window, dedups on the device's own record id stored inthoughts.metadata(idempotent, self-healing across outages, no local state file), maps via the adapter using the device's own structured output (no per-item LLM cost), embeds via OpenRouter, inserts intothoughts.Guardrails
thoughtsschema changes.Deno.envonly (no keys in code).deno check/deno lint/deno fmtclean.Adapters (separate PRs, build on this)
[integrations] Omi wearable capture[integrations] Limitless wearable capture🤖 Generated with Claude Code