{"_id":"@amirhosseinnouri/momgen","_rev":"7-5c9779be81d3bcadc9559f3a8d8657d3","name":"@amirhosseinnouri/momgen","dist-tags":{"next":"2.0.0-0","latest":"2.3.0"},"versions":{"1.0.0":{"name":"@amirhosseinnouri/momgen","version":"1.0.0","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","bun"],"license":"MIT","_id":"@amirhosseinnouri/momgen@1.0.0","maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"homepage":"https://github.com/amirhosseinNouri/momgen","bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"bin":{"momgen":"src/index.ts"},"dist":{"shasum":"8d984b434222dbcab83376c40ead61b3c53065e3","tarball":"https://registry.npmjs.org/@amirhosseinnouri/momgen/-/momgen-1.0.0.tgz","fileCount":33,"integrity":"sha512-8gl8JfeznswL1niAgySI8WmXdZKQq9+nmWa0IceNoClkQZS6Ix0ticIxbtafw+zPF2EEPz1ooIhewx50iGXHLw==","signatures":[{"sig":"MEQCICeepVjyRAXmEVslSxp4MwSejhwv5ZcqBA4PHlRveih+AiBmEPjFo65nYgxvtkxKtbHdeDrhK7pXxgsRMmY83QeTkQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":96905},"type":"module","module":"src/index.ts","engines":{"bun":">=1.2.0"},"gitHead":"42281f14800966bb4bdfcac9d496dfe83a47b592","scripts":{"test":"bun test","start":"bun run src/index.ts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"},"repository":{"url":"git+https://github.com/amirhosseinNouri/momgen.git","type":"git"},"_npmVersion":"11.16.0","description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"ai":"^7.0.48","zod":"^4.4.3","@clack/prompts":"^1.6.0","@ai-sdk/openai-compatible":"^3.0.20"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/bun":"^1.3.14","@types/node":"^26.0.1"},"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/momgen_1.0.0_1785968429864_0.5909792341346622","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@amirhosseinnouri/momgen","version":"1.1.0","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","bun"],"license":"MIT","_id":"@amirhosseinnouri/momgen@1.1.0","maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"homepage":"https://github.com/amirhosseinNouri/momgen","bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"bin":{"momgen":"src/index.ts"},"dist":{"shasum":"6c53a64ec826dad9f068edf518c8741dd2a56883","tarball":"https://registry.npmjs.org/@amirhosseinnouri/momgen/-/momgen-1.1.0.tgz","fileCount":33,"integrity":"sha512-f/wpDAzMvM/Ra78qiZC9nvOZ8bDm8dERDb9XQsdA0KQlbrdZ3TrUtvfKS26xkhHugWL1o+6+zreIySd2QsJ+TA==","signatures":[{"sig":"MEQCIB8gjlUbIHb2LKaE142/AhMV+57b6BRSIVbgAWz64SCAAiBm3jSPvsImNHqM8Y58t9BAqA3CaWD0Ra4ILLRAjY8TTw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":111251},"type":"module","module":"src/index.ts","engines":{"bun":">=1.2.0"},"gitHead":"570c43740131f95c2d7dc212b4fbf981839fac0a","scripts":{"test":"bun test","start":"bun run src/index.ts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"},"repository":{"url":"git+https://github.com/amirhosseinNouri/momgen.git","type":"git"},"_npmVersion":"11.16.0","description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"ai":"^7.0.48","zod":"^4.4.3","@clack/prompts":"^1.6.0","@ai-sdk/openai-compatible":"^3.0.20"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/bun":"^1.3.14","@types/node":"^26.0.1"},"peerDependencies":{"typescript":"^5"},"_npmOperationalInternal":{"tmp":"tmp/momgen_1.1.0_1786374878436_0.6938402479031014","host":"s3://npm-registry-packages-npm-production"}},"2.0.0-0":{"name":"@amirhosseinnouri/momgen","version":"2.0.0-0","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","node"],"license":"MIT","_id":"@amirhosseinnouri/momgen@2.0.0-0","maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"homepage":"https://github.com/amirhosseinNouri/momgen","bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"bin":{"momgen":"dist/index.js"},"dist":{"shasum":"028351410aa5fa39200add58f43cdd09d1577569","tarball":"https://registry.npmjs.org/@amirhosseinnouri/momgen/-/momgen-2.0.0-0.tgz","fileCount":6,"integrity":"sha512-ITXx+aOOCPAEMAkNn/4eI8Pijv4Avr3u+/j3MhOz8IBunr7uCaysaFhd0L5E6LL2b8R77OwFV5xX2O8DYL8rHg==","signatures":[{"sig":"MEUCIQDmB8SQylbHUfmOk55DA0AgYF34+GQg+qlhyPqbeVymUAIgG5fnZv36VQu+OFB197nKp9N4CyLjLwUykC3U5VUocjI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":101467},"main":"dist/index.js","type":"module","module":"dist/index.js","engines":{"node":">=20.0.0"},"gitHead":"1225b09587e2b930f42cb40395eff41a792d021d","scripts":{"test":"bun test","build":"rm -rf dist && rollup -c && chmod +x dist/index.js","start":"bun run src/index.ts","typecheck":"tsc --noEmit","preversion":"bun run typecheck && bun test && bun run build","prepublishOnly":"bun run typecheck && bun test && bun run build"},"_npmUser":{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"},"repository":{"url":"git+https://github.com/amirhosseinNouri/momgen.git","type":"git"},"_npmVersion":"11.16.0","description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"ai":"^7.0.48","zod":"^4.4.3","dotenv":"^17.4.2","@clack/prompts":"^1.6.0","@ai-sdk/openai-compatible":"^3.0.20"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.8.1","rollup":"^4.62.4","@types/bun":"^1.3.14","typescript":"^5.9.3","@types/node":"^26.0.1","@rollup/plugin-typescript":"^12.3.0"},"_npmOperationalInternal":{"tmp":"tmp/momgen_2.0.0-0_1786884700954_0.12622646733841192","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@amirhosseinnouri/momgen","version":"2.0.0","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","node"],"license":"MIT","_id":"@amirhosseinnouri/momgen@2.0.0","maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"homepage":"https://github.com/amirhosseinNouri/momgen","bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"bin":{"momgen":"dist/index.js"},"dist":{"shasum":"f420535478e463b2792813ccfbaf631b16a43787","tarball":"https://registry.npmjs.org/@amirhosseinnouri/momgen/-/momgen-2.0.0.tgz","fileCount":6,"integrity":"sha512-Y7VmLh/mPZ6Rfm+2h35ihZScvgIKY4l7TOD6ZMx4manZxr6OBeGxSUMeREjHisyJkCIxSMQ1PAX7IIYoCKYNWA==","signatures":[{"sig":"MEUCIQCHT8C398R4R7PpQvhygfam9WgL6JtDVcU8z53y4E5y3QIge6B27/jSznTldYYfcW3cwV4k0n5gaZ6XBXA018objzA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":101465},"main":"dist/index.js","type":"module","module":"dist/index.js","engines":{"node":">=20.0.0"},"gitHead":"127cb08932351ec1bad7717fd455af3cc8c759a8","scripts":{"test":"bun test","build":"rm -rf dist && rollup -c && chmod +x dist/index.js","start":"bun run src/index.ts","typecheck":"tsc --noEmit","preversion":"bun run typecheck && bun test && bun run build","prepublishOnly":"bun run typecheck && bun test && bun run build"},"_npmUser":{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"},"repository":{"url":"git+https://github.com/amirhosseinNouri/momgen.git","type":"git"},"_npmVersion":"11.16.0","description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"ai":"^7.0.48","zod":"^4.4.3","dotenv":"^17.4.2","@clack/prompts":"^1.6.0","@ai-sdk/openai-compatible":"^3.0.20"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.8.1","rollup":"^4.62.4","@types/bun":"^1.3.14","typescript":"^5.9.3","@types/node":"^26.0.1","@rollup/plugin-typescript":"^12.3.0"},"_npmOperationalInternal":{"tmp":"tmp/momgen_2.0.0_1786885003697_0.8106127504686851","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@amirhosseinnouri/momgen","version":"2.1.0","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","node"],"license":"MIT","_id":"@amirhosseinnouri/momgen@2.1.0","maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"homepage":"https://github.com/amirhosseinNouri/momgen","bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"bin":{"momgen":"dist/index.js"},"dist":{"shasum":"7e0d30960bfde0d9b01a8c2e146824d2d701ed40","tarball":"https://registry.npmjs.org/@amirhosseinnouri/momgen/-/momgen-2.1.0.tgz","fileCount":6,"integrity":"sha512-WSoDgEgfNACYh35Cd6NmGhsYK5TPnZ9RmtjviSIv0VpMwR1zoAPugMv68Un0PpfpjFGEfNprMHXWE0Lzl7wyzQ==","signatures":[{"sig":"MEYCIQCO3wZqztSg5mNnXlK2MketDdzRwW2vMCVRB/ig0h/v1wIhALHc6smcWqfRZNaQhAHS88j5hOpWYjty9faSlc+JJCQO","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":129055},"main":"dist/index.js","type":"module","module":"dist/index.js","engines":{"node":">=20.0.0"},"gitHead":"4176a70280adfd823be29abc9f8e422e2c348a49","scripts":{"test":"bun test","build":"rm -rf dist && rollup -c && chmod +x dist/index.js","start":"bun run src/index.ts","typecheck":"tsc --noEmit","preversion":"bun run typecheck && bun test && bun run build","release:major":"bun run scripts/release.ts major","release:minor":"bun run scripts/release.ts minor","release:patch":"bun run scripts/release.ts patch","prepublishOnly":"bun run typecheck && bun test && bun run build"},"_npmUser":{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"},"repository":{"url":"git+https://github.com/amirhosseinNouri/momgen.git","type":"git"},"_npmVersion":"11.16.0","description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"ai":"^7.0.48","zod":"^4.4.3","dotenv":"^17.4.2","@clack/prompts":"^1.6.0","@ai-sdk/openai-compatible":"^3.0.20"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.8.1","rollup":"^4.62.4","@types/bun":"^1.3.14","typescript":"^5.9.3","@types/node":"^26.0.1","@rollup/plugin-typescript":"^12.3.0"},"_npmOperationalInternal":{"tmp":"tmp/momgen_2.1.0_1786955758580_0.2730988256318505","host":"s3://npm-registry-packages-npm-production"}},"2.2.0":{"name":"@amirhosseinnouri/momgen","version":"2.2.0","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","node"],"license":"MIT","_id":"@amirhosseinnouri/momgen@2.2.0","maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"homepage":"https://github.com/amirhosseinNouri/momgen","bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"bin":{"momgen":"dist/index.js"},"dist":{"shasum":"52122b5445ce1c843409774abf6fe6c04a92bf18","tarball":"https://registry.npmjs.org/@amirhosseinnouri/momgen/-/momgen-2.2.0.tgz","fileCount":7,"integrity":"sha512-uFiILTf3FeOYpF4GYVGmLQRBRE34q7dNPbPMA4gTKpjuZkFMimSOMtrKbyGckAwTaOqrCdNMn+8FjdCH7ERumA==","signatures":[{"sig":"MEYCIQDFQEv5neV9lpTRnpMJTi7sbRM19yECxnAFCmVPNja3NwIhAIbzjMvzRAdc87JQi9/tzEgsQ+YTcHM9NlCeFVvUUc25","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":171667},"main":"dist/index.js","type":"module","module":"dist/index.js","engines":{"node":">=20.0.0"},"gitHead":"da50e0b4d9df5a9fda3a243cee7da865e161e063","scripts":{"test":"bun test","build":"rm -rf dist && rollup -c && chmod +x dist/index.js","start":"bun run src/index.ts","typecheck":"tsc --noEmit","preversion":"bun run typecheck && bun test && bun run build","release:major":"bun run scripts/release.ts major","release:minor":"bun run scripts/release.ts minor","release:patch":"bun run scripts/release.ts patch","prepublishOnly":"bun run typecheck && bun test && bun run build"},"_npmUser":{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"},"repository":{"url":"git+https://github.com/amirhosseinNouri/momgen.git","type":"git"},"_npmVersion":"11.16.0","description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"ai":"^7.0.48","zod":"^4.4.3","dotenv":"^17.4.2","@clack/prompts":"^1.6.0","@ai-sdk/openai-compatible":"^3.0.20"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.8.1","rollup":"^4.62.4","@types/bun":"^1.3.14","typescript":"^5.9.3","@types/node":"^26.0.1","@rollup/plugin-typescript":"^12.3.0"},"_npmOperationalInternal":{"tmp":"tmp/momgen_2.2.0_1787483881801_0.03898407885073385","host":"s3://npm-registry-packages-npm-production"}},"2.3.0":{"name":"@amirhosseinnouri/momgen","version":"2.3.0","description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","node"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/amirhosseinNouri/momgen.git"},"homepage":"https://github.com/amirhosseinNouri/momgen","bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"main":"dist/index.js","module":"dist/index.js","type":"module","bin":{"momgen":"dist/index.js"},"publishConfig":{"access":"public"},"engines":{"node":">=20.0.0"},"scripts":{"start":"bun run src/index.ts","build":"rm -rf dist && rollup -c && chmod +x dist/index.js","preversion":"bun run typecheck && bun test && bun run build","prepublishOnly":"bun run typecheck && bun test && bun run build","release:patch":"bun run scripts/release.ts patch","release:minor":"bun run scripts/release.ts minor","release:major":"bun run scripts/release.ts major","test":"bun test","typecheck":"tsc --noEmit"},"devDependencies":{"@rollup/plugin-typescript":"^12.3.0","@types/bun":"^1.3.14","@types/node":"^26.0.1","rollup":"^4.62.4","tslib":"^2.8.1","typescript":"^5.9.3"},"dependencies":{"@ai-sdk/openai-compatible":"^3.0.20","@clack/prompts":"^1.6.0","ai":"^7.0.48","dotenv":"^17.4.2","zod":"^4.4.3"},"gitHead":"60de78d8fa1bb20d9bfe8509075b8f8609a4a622","_id":"@amirhosseinnouri/momgen@2.3.0","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-Z4f48skLeZpXVxes1drckmHG8b3G7/avCP1PoDq4uNmHnPk+UTUW89nIdLxKRHgvi6Hjyd0b2N5YjbXb7ReAKw==","shasum":"365669c23363abce966156cadb1eb33832036288","tarball":"https://registry.npmjs.org/@amirhosseinnouri/momgen/-/momgen-2.3.0.tgz","fileCount":7,"unpackedSize":194303,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEzuOBzQ4/6QUc3SJWEpln55ucgllqkiVn7Y1HZ+F3rCAiEAiyZbEJMJG9DsxarH3ooYgB3Rot0c6WgJygpsVNQdStQ="}]},"_npmUser":{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"},"directories":{},"maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/momgen_2.3.0_1787484688651_0.6056802336790859"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-05T22:20:29.717Z","modified":"2026-08-23T11:31:28.947Z","1.0.0":"2026-08-05T22:20:30.023Z","1.1.0":"2026-08-10T15:14:38.594Z","2.0.0-0":"2026-08-16T12:51:41.107Z","2.0.0":"2026-08-16T12:56:43.847Z","2.1.0":"2026-08-17T08:35:58.718Z","2.2.0":"2026-08-23T11:18:01.946Z","2.3.0":"2026-08-23T11:31:28.789Z"},"bugs":{"url":"https://github.com/amirhosseinNouri/momgen/issues"},"license":"MIT","homepage":"https://github.com/amirhosseinNouri/momgen","keywords":["minutes-of-meeting","mom","transcription","elevenlabs","scribe","whisper","meeting-notes","cli","node"],"repository":{"type":"git","url":"git+https://github.com/amirhosseinNouri/momgen.git"},"description":"Turn a meeting recording into a short Minutes of Meeting markdown file.","maintainers":[{"name":"amirhosseinnouri","email":"Amir.h.nouri2000@gmail.com"}],"readme":"# momgen\n\n**[momgen-ai.vercel.app](https://momgen-ai.vercel.app/)**\n\nTurn a meeting recording (audio or video) into a short, to-the-point **Minutes of Meeting**\nmarkdown file: [ElevenLabs Scribe](https://elevenlabs.io) writes the transcript, and a chat\nmodel of your choosing writes the minutes.\n\n## Setup\n\nRun it straight from the registry with whichever package manager you already have — there\nis nothing to clone and nothing to install globally:\n\n```bash\nnpx  @amirhosseinnouri/momgen ./video.mp4\npnpx @amirhosseinnouri/momgen ./video.mp4\nbunx @amirhosseinnouri/momgen ./video.mp4\n```\n\nAll three are equivalent; they differ only in which registry client fetches the package.\nThe published `bin` is plain JavaScript built for **Node `>=20`**, so no Bun is required to\nrun it — Bun is only the development runtime for this repository.\n\nOne thing does have to be on `PATH` first: **ffmpeg** and **ffprobe**. Every local audio\nstep shells out to them, and neither is bundled.\n\n```bash\nbrew install ffmpeg          # or apt install ffmpeg, winget install Gyan.FFmpeg\n```\n\nCloning is for changing the code — the CLI itself needs no checkout. If that is what you\nare here for, see [Development](#development).\n\nThen save your two keys once, with the CLI:\n\n```bash\nnpx @amirhosseinnouri/momgen config set --elevenlabs_api_key sk-... --llm_api_key sk-...\n```\n\nThat writes `~/.momgen/config.json` — owner-readable only — and every run picks it up no\nmatter which directory you start it from.\n\nThe same settings can come from the environment instead, which is what a `.env` in the\ndirectory you run momgen from gives you:\n\n```\nLLM_API_KEY=...          # minutes\nELEVENLABS_API_KEY=...   # transcription\n```\n\nEnvironment variables win over the saved file, so a one-off\n`LLM_MODEL=... momgen ./video.mp4` overrides a saved default without erasing it. A blank\nvariable does not: `LLM_MODEL=` means unset, not \"forget what I saved\".\n\n## Configuration\n\n```bash\nmomgen config set --llm_model qwen3:30b   # save one or more settings\nmomgen config list                        # everything saved, API keys masked\nmomgen config get llm_model               # one value, unmasked, for scripts\nmomgen config unset llm_model             # forget a setting\nmomgen config path                        # where the file lives\nmomgen config                             # the list of settings\n```\n\nEvery setting has a saved name and an environment variable, the same string in different\ncases: `--llm_api_key` is `LLM_API_KEY`, `--segment_seconds` is `SEGMENT_SECONDS`. Values\nare checked when you set them, so a price that is not a number or a segment length of `0`\nis refused there and then rather than at the start of the next run. `MOMGEN_CONFIG_PATH`\npoints momgen at a different file if you keep more than one profile.\n\nGive the ElevenLabs key the **`user_read`** permission as well as speech-to-text. It is not\nrequired to transcribe, but it is what lets the cost report show the credits left on the\naccount — and an empty account is otherwise invisible: ElevenLabs drops the connection\npart-way through an upload rather than refusing it, and the run fails on a socket error\nminutes in. With `user_read`, momgen stops before sending anything and says the balance is\nspent.\n\nThe minutes model is reached through the [AI SDK](https://ai-sdk.dev) over a plain\nOpenAI-compatible `/chat/completions` endpoint, so any provider speaking that dialect works\n— point `LLM_BASE_URL` at it and name the model in `LLM_MODEL`:\n\n```\n# OpenCode Zen (the default)\nLLM_BASE_URL=https://opencode.ai/zen/go/v1\nLLM_MODEL=deepseek-v4-flash\n\n# OpenRouter\nLLM_BASE_URL=https://openrouter.ai/api/v1\nLLM_MODEL=anthropic/claude-sonnet-5\n\n# a local vLLM / Ollama\nLLM_BASE_URL=http://localhost:11434/v1\nLLM_MODEL=qwen3:30b\n```\n\n## Agent setup\n\nThe setup above is also packaged as a skill, `momgen-setup`, so a coding agent can do it\nfor you: check the prerequisites, walk you through both keys, work out where the `.env`\nhas to live for the way you invoke momgen, and finish with a verification run.\n\nA second skill, `momgen-add-template`, covers [Templates](#templates) — ask an agent for\nminutes shaped around your standup, retro or client call, or for a warmer or more formal\nvoice, and it writes the sections and the style, saves them, selects them, and shows you\nthe result.\n\nInstall them with the [skills](https://github.com/vercel-labs/skills) CLI, which reads the\nskills straight out of this repository — no clone, and nothing to install from the registry:\n\n```bash\nnpx skills add amirhosseinNouri/momgen\n```\n\nIt finds both skills under `skills/`, asks which of your agents to install into (Claude\nCode, Cursor, Codex, …) and links them into each one's skills directory. Useful flags:\n\n```bash\nnpx skills add amirhosseinNouri/momgen -g          # user-level instead of this project\nnpx skills add amirhosseinNouri/momgen --all       # every agent, no prompts\nnpx skills add amirhosseinNouri/momgen -l          # just list what the repo offers\n```\n\nThen ask the agent to \"set up momgen\" and it takes over from there.\n\nIf you would rather not add a tool: the skills are plain markdown with no tooling\nassumptions beyond a shell, so point any agent at `skills/momgen-setup/SKILL.md` or\n`skills/momgen-add-template/SKILL.md` directly, or link them yourself — Claude Code\nauto-discovers skills under `.claude/skills/`:\n\n```bash\nmkdir -p .claude/skills\nln -s ../../skills/momgen-setup .claude/skills/momgen-setup\nln -s ../../skills/momgen-add-template .claude/skills/momgen-add-template\n```\n\n`skills/momgen-setup/references/env-vars.md` holds the full variable reference, which the\nagent loads only when a specific variable comes up.\n\nBoth skills ship in the npm package as well, so `npm i @amirhosseinnouri/momgen` puts them\nunder `node_modules/@amirhosseinnouri/momgen/skills/` — also valid symlink targets.\n\n## Usage\n\n```bash\nnpx @amirhosseinnouri/momgen ./meeting.mp3     # or pnpx / bunx\nnpx @amirhosseinnouri/momgen ./standup.mp3 --template standup\n```\n\nIt takes an audio or video file, or no argument at all, in which case it prompts for one.\n`--template` picks the section list the minutes are built from — see [Templates](#templates).\n\nThe `.env` is read from the directory you run in, not from wherever the package was\ninstalled. That is the usual reason an `npx` run reports a missing key while a `.env` sits\none directory over. Export the variables from your shell profile if you run momgen from\narbitrary directories.\n\nEach run writes to a fresh `output/<source-name>-<timestamp>/` directory containing\n`transcript.md` and `mom.md`. `output/` is git-ignored.\n\n## Templates\n\nOut of the box the minutes have a fixed shape — Attendees, Agenda, Decisions, Action Items,\nDiscussion Summary — written tersely. A template replaces both:\n\n```bash\nmomgen template list                          # every template, its sections and its style\nmomgen template add standup --file ./standup.md\nmomgen template show standup                  # one template\nmomgen template remove standup\nmomgen template path                          # where the files live\n```\n\nA template is a Markdown file with an optional `---` block on top:\n\n```markdown\n---\ndescription: Quarterly board meeting\nstyle: |\n  Formal and impersonal. Third person, no contractions.\n  Attribute every decision to the person who made it.\n---\n\n# Board Meeting\n## Present\n## Resolutions\n## Action Items (markdown checklist)\n```\n\nIt controls exactly two things — the **sections** in the body, and the **style** the prose\ninside them is written in. The `---` block takes those two fields and `description`, which\nis for you and never reaches the model; a misspelt field is an error rather than a setting\nthat silently never applies. A file with no block at all is a valid template written in\nmomgen's default style.\n\nWhat a template cannot change is momgen's own instruction: that the model is an expert\nmeeting minutes writer, that it writes in the configured language, and that it uses\n**exactly** the sections it was given. The last one is the reason the structure holds — the\nminutes land in a file nobody reviews before reading, so a run that invents its own headings\nis worse than one that leaves a section empty. Style is voice, not the job: formality,\nperson, sentence length, how much detail survives. The language is `mom_language`, not a\nstyle.\n\nChanging only the tone does not mean restating the sections — with no body, `add` reuses the\ndefault template's:\n\n```bash\nmomgen template add warm --style 'Warm and conversational. Full sentences, first person plural.'\n```\n\nTemplates are plain files at `~/.momgen/templates/<name>.md`, beside `config.json` — so\n`MOMGEN_CONFIG_PATH` moves a profile's templates along with its settings, and sharing one\nis copying a file. `momgen template add` also reads the body from stdin, and `--style` wins\nover a `style:` already in the file, which is what makes both scriptable:\n\n```bash\ncat <<'MD' | momgen template add retro --style 'Bullet fragments, not sentences.'\n# Retro\n## Went well\n## Did not go well\n## Action Items (markdown checklist)\nMD\n```\n\nPick one for a single run with `--template <name>`, or for every run with\n`momgen config set --mom_template <name>`. `MOM_TEMPLATE` in the environment overrides the\nsaved setting, and `--template` overrides both. With none of them the built-in `default` is\nused — it has no file, so a fresh install always has a working template, and saving one\nnamed `default` shadows it.\n\nThe name is resolved before anything is uploaded, so `--template standupp` fails\nimmediately rather than after the transcription has been paid for, and the run prints what\nthe minutes will be in a **Minutes** panel above the cost confirmation:\n\n```\n◇  Minutes ─────────────────────────────────────────╮\n│                                                   │\n│  Template    retro                                │\n│  Language    English                              │\n│  Style       Bullet fragments, not sentences.     │\n│                                                   │\n│  # Retro                                          │\n│  ## Went well                                     │\n│  ## Did not go well                               │\n```\n\n## How it works\n\n1. **Audio extraction** — for video inputs, ffmpeg strips the audio to mp3. Cached by the\n   video's SHA-256, so re-running the same file skips the decode. The audio is re-timed\n   (`aresample`) because call recordings often carry jittery timestamps that the mp3 muxer\n   would otherwise drop speech over. If the extracted audio is materially shorter than the\n   video's declared duration — the signature of an interrupted download, whose MP4 header\n   still claims the full length — the run warns rather than quietly transcribing a fraction\n   of the meeting.\n2. **Silence removal** — transcription is billed per second of audio uploaded, and silence\n   transcribes to nothing, so gaps longer than a second are cut out before upload. A short\n   pause is left in place of each gap (`stop_silence`), otherwise the words on either side\n   run together and come back as one mangled token. If the filter eats almost the whole\n   recording — a wrong threshold for an unusually quiet source — the original audio is used\n   instead, since paying to transcribe a mangled file is worse than paying for the silence.\n3. **Cost estimate** — the speech-only audio is split into segments, segments already in\n   the cache are subtracted, and the run prints what is left to upload with its price\n   before asking to continue. Nothing reaches the provider until that prompt is answered.\n4. **Transcription** — each uncached segment goes to Scribe and the full response is\n   written to the cache before anything else runs, so an interrupted run resumes where it\n   stopped and never pays for the same audio twice. Scribe is left to detect the language\n   itself, which it does well on mixed Persian/English speech — forcing a code makes the\n   loanwords worse.\n5. **Minutes** — the full transcript is streamed to the configured chat model, which writes\n   the minutes under the selected template's sections and in its style (by default:\n   Attendees / Agenda / Decisions / Action Items / Discussion Summary, written tersely —\n   see [Templates](#templates)).\n   Streaming is not cosmetic: a reasoning model can think for minutes before its first\n   token, and a non-streamed request sits idle long enough to be killed in transit. The\n   run aborts only after five minutes with no delta at all — reasoning counts as progress.\n\n## Configuration\n\n| Env var | Default | Purpose |\n|---|---|---|\n| `LLM_API_KEY` | — | required |\n| `ELEVENLABS_API_KEY` | — | required |\n| `LLM_BASE_URL` | `https://opencode.ai/zen/go/v1` | OpenAI-compatible endpoint, without `/chat/completions` |\n| `LLM_MODEL` | `deepseek-v4-flash` | minutes model |\n| `ASR_LANGUAGE` | unset (auto-detect) | language hint for Scribe |\n| `ASR_PRICE_PER_HOUR` | `0.22` | rate used for the estimate |\n| `ELEVENLABS_STT_MODEL` | `scribe_v1` | Scribe model |\n| `SILENCE_THRESHOLD` | `-35dB` | below this counts as silence |\n| `SILENCE_MIN_SECONDS` | `1` | shorter gaps are left alone |\n| `SEGMENT_SECONDS` | `900` | audio segment length |\n| `MOM_LANGUAGE` | `English` | language of the minutes |\n| `MOM_TEMPLATE` | `default` | name of the template — sections and style — see [Templates](#templates) |\n\nNothing reads `process.env` outside `src/lib/config/`. The table above is that module's\nzod schema restated: a variable that is unset — or set to an empty string, which a\nhalf-filled `.env` line produces — falls back to the default, and one that is set to\nnonsense (`SEGMENT_SECONDS=nine`, `SEGMENT_SECONDS=-5`, a malformed `LLM_BASE_URL`) fails\nat startup naming the variable, rather than surfacing as a `$NaN` cost estimate several\nminutes later. `LLM_API_KEY` is checked at startup too, even though the minutes are the\nlast step — a run that dies there has already paid for the transcription.\n\nCaches live in `$TMPDIR/momgen-cache`: extracted audio, speech-only audio, segments, and\nScribe responses (keyed by model and language hint, so changing either re-transcribes).\nEverything ffmpeg produces is written to a temporary name and moved into place only once\nit exits cleanly, so an interrupted run never leaves a short file behind for the next run\nto read back as a complete one.\n\n## Development\n\nOnly needed if you are changing momgen itself — to use it, see [Setup](#setup).\n\n```bash\ngit clone https://github.com/amirhosseinNouri/momgen\ncd momgen\nbun install\nbun start ./video.mp4      # runs src/index.ts directly, no build\n```\n\nBun is the development runtime: it runs the TypeScript sources as-is and provides the test\nrunner. What gets published is different — `bun run build` compiles `src/` into a single\nESM file at `dist/index.js` with rollup (`rollup.config.mjs`), prefixed with\n`#!/usr/bin/env node`, and that file is the package's `bin`. Runtime dependencies stay\nexternal and are resolved from `node_modules` as normal; only the project's own modules are\nbundled.\n\n```bash\nbun run build             # dist/index.js + sourcemap\nnode dist/index.js ./video.mp4\nbun test\nbun run typecheck\n```\n\n`prepublishOnly` runs typecheck, tests, and the build, so a publish cannot ship an artifact\nthat does not compile. `dist/` is git-ignored and rebuilt on every publish.\n\nThe one thing Bun does that Node does not is load `.env` automatically, so `src/env.ts`\ndoes it explicitly with dotenv. It is imported by the entry point only — never by the\nlibrary modules, which would put the repository's own `.env` underneath the tests.\n\n## Layout\n\nEach module is a directory holding the implementation, its types, its tests, and a barrel\nthat is the only thing other modules import from:\n\n```\nsrc/lib/video/\n  video.ts         implementation\n  video.types.ts   exported interfaces\n  video.test.ts    unit tests\n  index.ts         barrel — `import { extractAudio } from '../video'`\n```\n\n| Module | Role |\n|---|---|\n| `src/index.ts` | entry point — nothing but `run()` |\n| `src/env.ts` | loads `.env` for the Node build; imported by the entry point only |\n| `src/lib/config/` | every env var and every default, in one schema |\n| `src/lib/proc/` | the only place a child process is spawned — ffmpeg/ffprobe go through it |\n| `src/lib/cli/` | orchestration and the terminal UI: input → audio → cost prompt → transcript → minutes |\n| `src/lib/video/` | video detection, audio extraction, the truncated-download check |\n| `src/lib/audio/` | ffmpeg/ffprobe work: hashing, duration, silence removal, segmenting |\n| `src/lib/asr/` | transcription planning, cost estimate, per-segment cache, retries |\n| `src/lib/elevenlabs/` | Scribe HTTP client and the cost report it bills by |\n| `src/lib/llm/` | streamed chat via the AI SDK + the minutes prompt |\n| `src/lib/template/` | the sections and style the minutes are written to — read, write, resolve |\n| `src/lib/output/` | run directory naming and creation |\n| `output/` | generated runs, git-ignored |\n| `dist/` | the built `bin`, produced by `bun run build`, git-ignored |\n| `skills/momgen-setup/` | the setup skill an agent follows — see [Agent setup](#agent-setup) |\n| `skills/momgen-add-template/` | the template skill an agent follows — see [Templates](#templates) |\n| `web/` | the landing page (Next.js + shadcn/ui) — see `web/README.md` |\n\nThe tests never call a provider — the ASR and chat clients are driven through a stubbed\n`fetch`, and `planTranscription` takes an injected provider. The ffmpeg-backed tests build\ntheir own two-second fixtures with `lavfi` and skip themselves when ffmpeg is absent.\n","readmeFilename":"README.md"}