Repository navigation
feat(notes): local-first voice memo transcription into notes (ODIAA-2331) - #27
Merged
Merged
Conversation
…331) Add `tb notes transcribe <audioFile>` and MCP tool `note_transcribe`, transcribing audio to text with a locally installed speech-to-text engine (whisper.cpp or faster-whisper, auto-detected on PATH or via TB_WHISPER_CPP_BIN/TB_FASTER_WHISPER_BIN) and saving the result as a note with source/engine metadata in its front matter. No audio or text ever leaves the machine: there is no cloud STT path and no API keys. When no local engine is found, the error names both supported engines and how to install them. Cloud STT is a separate vendor decision left for the PR to route through CTO/CEO approval. Tests cover the stt.js engine-selection/error paths and the CLI/MCP surfaces using stub engine binaries, with no real audio processing required. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- SPEC.md: keep the transcribe write-up, take main's renamed "Calendars and calendar events" heading, and recompute the CLI/MCP command-count table from the actual merged source (71 CLI leaf commands, 38 MCP tools) rather than either side's stale numbers. - test/mcp-test.mjs: update the two hardcoded tools/list-length assertions to 38 (main's 37 plus this branch's note_transcribe), confirmed by the actual tools/list response after merging. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
main advanced with PR #31 (deterministic skills: skill_today/week/clashes/from and lib/skills.js), which touched the same files as the transcribe branch. - cli/src/cli.js, mcp/src/tools.js: additive import conflicts — kept both the stt.js transcribe import and the lib/skills.js skill imports. - SPEC.md: recomputed every CLI/MCP command-count mention from the merged source (75 CLI leaf commands via `.action(` count, 42 MCP tools via tool-definition count), including two counts that were already stale before this merge (architecture diagram, "curated tools" prose). - test/mcp-test.mjs: updated the three hardcoded tools/list-length assertions to 42, confirmed by the live tools/list response (81/81 MCP tests passing). Full test:all and lint pass clean (lint's one failure is an unrelated missing built XPI artifact). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
tb notes transcribe <audioFile>and MCP toolnote_transcribe: audio → text → saved note, withsource(voice-memo:<filename>) andenginerecorded in the note's front matter.whisper-cli/whisper-cpp) or faster-whisper (whisper-ctranslate2) binary onPATH, or viaTB_WHISPER_CPP_BIN/TB_FASTER_WHISPER_BIN/TB_WHISPER_CPP_MODELenv overrides. If neither is found, raises a cleanNO_ENGINEerror naming both engines and how to install/configure them.cli/src/stt.js(+ self-contained mirrormcp/src/stt.js) →tb notes transcribeincli/src/cli.js→note_transcribeinmcp/src/tools.js. No new extension route was needed (transcription runs entirely against a local file and a local subprocess, unlikenote_to_draftwhich reuses the already-classified/composeextension route), soextension/src/access-control.jsis unchanged.SPEC.md(tool catalog + counts: CLI 43→44, MCP 21→22),docs/COMMANDS.md,CHANGELOG.md,skills/thunderbird-cli/SKILL.md(tool table + CLI-mapping table).cli/src/stt.js/mcp/src/stt.jscoverage using stub engine binaries (test/fixtures/stub-whisper-cpp.mjs,test/fixtures/stub-faster-whisper.mjs) for the no-engine, engine-selection, model-required, unknown-engine, missing-audio, engine-failure, and end-to-end transcript→note round-trip paths, plus the newnote_transcribeMCP tool tests. Also fixed a latenttest/docs.test.mjsfragility where Commander's help-text line-wrapping (triggered by the new longtranscribecommand signature) was mis-parsed as bogus subcommands.Cloud STT trade-off (for CTO → CEO routing, not shipped here)
Per ODIAA-2331/ODIAA-2306, any cloud speech-to-text provider is a separate vendor/stack decision requiring approval before it ships. This PR ships local-only engines; the options below are informational for that future decision:
Recommendation: keep Option A as the only shipped path; revisit Option B only if user feedback shows the local-engine install friction is a real adoption blocker, and only after CTO/CEO sign-off on vendor choice, data handling, and cost.
Test plan
npm run test:notes— 100 passed, 0 failed (includes new stt.js + transcribe round-trip cases)npm run test:mcp— 60 passed, 0 failed (includes newnote_transcribetool cases, tool count 21→22)npm run test:docs— 84 passed, 0 failed (includes fix for Commander help-text line-wrap mis-parsing)npm run test:all— all suites passnpm run lint— clean (pre-existing manifest permission warnings unrelated to this change)NO_ENGINEclean error path (no whisper.cpp/faster-whisper installed in this environment) names both engines and install hints🤖 Generated with Claude Code