| name | obsidian-capture |
| description | Process voice captures from iOS Siri dictation into the Obsidian daily note. Reads timestamped entries from an iCloud Drive capture file, scores transcription confidence, corrects Siri-mangled proper nouns using vault vocabulary, inserts cleaned entries into the daily note, and archives the raw content. Use this skill whenever the user says "process my captures", "voice captures", "get my voice notes", "import my random thoughts", "process random thoughts", "check my captures", "what did I dictate", "run obsidian capture", or mentions the Siri capture file, dictation processing, or voice note filing.
|
Obsidian Capture
Process voice captures from iOS Siri dictation into the Obsidian daily note. An iOS Shortcut appends timestamped dictations to a flat text file via iCloud Drive. This skill reads that file, cleans up transcription errors, inserts entries into the daily note, archives the raw content, and clears the capture file.
Model routing
Delegate execution to the vault-operator agent (pinned to Sonnet). This work is deterministic CLI orchestration — dedup, insert, archive, clear — and doesn't need Opus. Brief the agent with "run the obsidian-capture skill" and let it follow this SKILL.md. Only the caller's main session needs Opus for disambiguating unparseable entries if the agent escalates.
Capture File
The iOS Shortcut writes to an iCloud Drive path with spaces and tildes that would trigger permission prompts on every access. Two bundled shell scripts encapsulate this path:
read-captures.sh — outputs the capture file contents (exit 1 if missing)
clear-captures.sh — clears the file with cp /dev/null (a clean file-write event that iCloud syncs reliably)
The scripts live in this skill's directory. Run them with:
bash .claude/skills/obsidian-capture/read-captures.sh
bash .claude/skills/obsidian-capture/clear-captures.sh
The capture file has one entry per line, timestamped:
[2026-03-08 14:32:15] Kirk mentioned the lease clause might block subletting dig into this
[2026-03-08 14:45:03] Idea repo sync skill should generate file class repo notes with language and status front matter
If read-captures.sh exits non-zero or returns empty output, report "No captures to process" and stop.
Multi-host safety
This skill can run from any Mac signed into the same Apple ID — the iCloud Shortcuts file is visible to all of them. The daily note timestamp dedup (matching **HH:MM:SS**) prevents duplicate insertions if two hosts race on the same entries. The cp /dev/null clear is idempotent.
Processing Pipeline
Step 0: Preflight — verify obsidian CLI
Before doing anything else, confirm the obsidian CLI is reachable:
obsidian vault
This should return the vault name and path. If it errors with "Unable to connect to main process", Obsidian isn't running or the CLI can't reach it. Report the error and stop — the skill depends on the CLI for daily note creation and vault queries. Ask the user to open Obsidian and try again.
Step 1: Read the capture file
bash .claude/skills/obsidian-capture/read-captures.sh
If exit code is non-zero or output is empty, report "No captures to process" and stop. Otherwise, parse each line into (timestamp, text). Lines that don't match [YYYY-MM-DD HH:MM:SS] ... should be flagged as unparseable and included as low-confidence entries.
Step 2: Build the vault vocabulary
Before scoring entries, build a correction dictionary from the vault. This vocabulary powers the fuzzy-matching that fixes Siri's mistakes.
Sources (run these in parallel where possible):
-
Note titles — use Glob to list filenames from 1p/ and 2a/:
Glob: 1p/**/*.md
Glob: 2a/**/*.md
Extract the note titles (filenames without .md) as vocabulary terms.
-
Tag vocabulary:
obsidian tags counts sort=count
-
Person names — list the people directory:
Glob: 3r/ppl/*.md
Extract first and last names from the filenames.
From these results, extract:
- Project/area names: NWHub, StoneGynOnc, skivalet, LithosUplift, etc.
- Person names: first and last names from person notes
- Technical terms: fileClass, frontmatter, Dataview, Templater, etc.
- Tag vocabulary: the tag hierarchy and its terms
Keep this as a flat list of known terms for fuzzy matching. You don't need to be exhaustive — focus on proper nouns and domain-specific terms that Siri is most likely to mangle.
Step 3: Score and clean each entry
For each entry, assess transcription confidence:
High confidence — Short, uses common words, no ambiguity. Apply light cleanup only:
- Add missing terminal punctuation
- Capitalize sentence starts
- No other changes needed
Medium confidence — Contains words that look like mangled proper nouns or technical terms. These are the entries where the vault vocabulary earns its keep. Common Siri patterns:
- Compound words split apart: "file class" → "fileClass", "front matter" → "frontmatter"
- Proper nouns phonetically garbled: "in W hub" → "NWHub", "stone gyn onc" → "StoneGynOnc"
- Names slightly off: "Kurt" when vault has "Kirk", "pan" when vault has "Pam"
- Technical terms normalized: "data view" → "Dataview", "template er" → "Templater"
For medium-confidence entries, use the vault vocabulary to correct likely misrecognitions. When a word or phrase fuzzy-matches a vault term (sounds similar, is a plausible Siri error), substitute the correct term. If you make corrections, the entry will be marked as AI-edited in the output.
Low confidence — Long and rambling, heavily garbled, or contains ambiguous references where you can't confidently determine intent. These get a ⚠️ marker so the user knows to review them. Still apply what cleanup you can (punctuation, obvious fixes), but don't guess at proper nouns.
Step 4: Group entries by date
Entries in the capture file may span multiple dates. Group them by the date portion of the timestamp. Process each date's entries into that date's daily note.
Step 5: Insert into daily note
For each date with entries:
-
Get the daily note content:
obsidian daily:read
(For dates other than today, read the file directly at 0.periodic/YYYY/Daily/MM/YYYY-MM-DD.md)
If the daily note doesn't exist, create it via the obsidian CLI before proceeding:
obsidian create path="0.periodic/YYYY/Daily/MM/YYYY-MM-DD.md" template="Daily Template"
This uses the vault's active Daily Template with full Templater resolution (frontmatter, prev/next nav links, task queries). Important: always verify the file doesn't already exist before calling create — if it does, the CLI appends " 1" to the filename instead of erroring, creating an unwanted duplicate. Use Glob or Read to check first.
After creating, read the new file to get its contents for insertion point detection.
-
Find the insertion point. In priority order, insert ## Voice Captures before the first of these that exists:
## Breadcrumbs
## Inbox Processing Observations
# WebClips
If none exist, insert after ### Habits (end of Journal subsections).
-
Check if ## Voice Captures already exists (the skill may run multiple times per day). If it does:
- Append new entries — don't replace existing ones
- Skip duplicates — match on full timestamp
**HH:MM:SS** to avoid re-inserting (HH:MM alone can collide when entries are seconds apart)
- Update the entry count in the heading
-
Use the Edit tool for mid-file insertion (the CLI's daily:append only appends to the end).
Output format
## Voice Captures (3 entries)
- **14:32:15** — Kirk mentioned the lease clause might block subletting. Dig into this.
- **14:45:03** — _(edited)_ Idea: repo-sync skill should generate `fileClass: repo` notes with language and status frontmatter.
- **16:12:44** — ⚠️ Need to check the "NWHub" transition doc before Thursday meeting.
Format rules:
- Each entry:
- **HH:MM:SS** — content (use full timestamp including seconds to avoid collisions between entries made seconds apart)
- Action items: If an entry is clearly a task or follow-up ("call X", "follow up on", "don't forget", "need to check"), render as
- [ ] **HH:MM:SS** — content instead. Don't force it — many captures are journal-style observations, not tasks. Only use checkboxes when the intent is obvious.
- Entries where AI corrections were applied: prefix content with
*(edited)*
- Low-confidence entries: prefix content with
⚠️
- Preserve the original meaning — clean up transcription, don't rewrite intent
- Add punctuation and capitalization but don't restructure sentences
Step 6: Archive raw content
Archive the raw capture file content (before any cleaning) to preserve Siri's exact output:
archive/ObsidianCapture/capture-YYYY-MM-DD.raw.txt
(Path relative to vault root: /Users/mstone/dev/vaults/tyee/archive/ObsidianCapture/)
- The archive directory should already exist. Only create it if missing (check with Glob or ls first — avoid unconditional
mkdir to prevent unnecessary permission prompts)
- Append to the archive file if it already exists (multiple runs per day are valid)
- Only archive entries for the date being processed — if the capture file spans multiple dates, each date's raw lines go to that date's archive file
Step 7: Clear the capture file
After all entries have been processed, inserted, and archived, clear the iCloud source file to prevent re-processing:
bash .claude/skills/obsidian-capture/clear-captures.sh
Run History
After a successful run, append a JSON entry to zz_config/skill_history/obsidian-capture.md so usage can be audited. Create the file on first run with obsidian create path="zz_config/skill_history/obsidian-capture.md" template="Base Template" if missing. Append via obsidian append.
Resolve hostname first, in its own Bash call, so it doesn't appear as $(...) in the content= arg (shell substitution triggers a permission prompt even when obsidian append * is allowlisted):
hostname -s
Then substitute the literal value into the JSON:
{"date": "YYYY-MM-DD", "host": "<literal-hostname>", "entries": N, "dates_touched": ["YYYY-MM-DD", ...], "edited": N_ai_corrected, "low_confidence": N_warned}
Skip the append when there were no entries to process (avoids polluting the log with no-ops).
Edge Cases
- Empty or missing capture file: Report "No captures to process" and stop
- Empty entries (valid timestamp but no text): Skip these entirely — they're accidental Siri triggers with no content. Don't count them in the entry total.
- Unparseable lines: Include as low-confidence with ⚠️ marker, using "??" as the time
- Daily note doesn't exist: Create it from the scaffold (see Step 5), then insert captures as normal. Report which daily notes were created.
- All entries are for past dates: Process each date into its respective daily note, creating any missing daily notes from the scaffold.
Dependencies
obsidian CLI for daily:read, daily:path, search, tags counts
- Edit tool for mid-file insertion into the daily note
- The vault is at
/Users/mstone/dev/vaults/tyee