TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
Steno records your meetings from your computer's own audio, transcribes and summarises them on-device, and writes plain Markdown you own. No bot in the call. No cloud account. Audio never leaves the m
ProductivityRust · SwiftGitHub @NicolaiSchmidOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Steno records your meetings from your computer's own audio, transcribes and summarises them on-device, and writes plain Markdown you own. No bot in the call. No cloud account. Audio never leaves the machine.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Steno records your meetings without joining them, turns the recording into a summary,
transcript and tasks on your own Mac, and writes the result into your Obsidian vault.
No bot in the call. No cloud account. No subscription. Audio never leaves the machine.
Status: release candidate. v1 is code-complete and shipping as pre-releases while
the last manual checks on real hardware run. Track the first stable release in
issue #74. The full scope and every
settled decision live in .plans/2026-09-24-initial-scope.md.Read the full README ↗Status: release candidate. v1 is code-complete and shipping as pre-releases while the last manual checks on real hardware run. Track the first stable release in issue #74. The full scope and every settled decision live in
.plans/2026-09-24-initial-scope.md.
Most meeting recorders join your call as a participant, upload the audio to their servers and keep your notes behind their login. Steno takes the opposite route:
| Hosted bot recorders | Steno | |
|---|---|---|
| Captures audio by | A bot joins the meeting | Core Audio taps the apps already playing on your Mac |
| Everyone on the call sees | "Notetaker has joined" | Nothing |
| Audio is processed | In the vendor's cloud | On your Mac, after the meeting |
| Notes live in | The vendor's app | Plain files in your Obsidian vault |
| Works for | Supported video platforms | Zoom, Teams, Meet, FaceTime, Slack, phone calls via Continuity, in-person meetings |
| Cost | Monthly subscription | Free, open source, your own LLM endpoint |
It was built to match the day-to-day quality of commercial meeting recorders for one person and their friends, with files instead of lock-in.
Steno is a signed and notarized Steno.app for macOS 15 or later on Apple Silicon.
Pick one of the three routes; all three install the same release build.
Homebrew (recommended, keeps itself updated through Sparkle)
brew tap nicolaischmid/tap && brew install --cask steno
Direct download
Grab Steno-<version>.dmg from the
latest release and drag the app
to /Applications.
Nix (aarch64-darwin, installs the released app unchanged)
nix profile install github:NicolaiSchmid/steno#steno
On first launch Steno walks you through the three permissions it needs: system audio capture, microphone, and optionally calendar access for meeting titles and attendee names. Then point it at your Obsidian vault and an OpenAI-compatible endpoint, and you are done.
The tap (NicolaiSchmid/homebrew-tap) follows every release, release candidates included. The installed app updates itself through Sparkle, which offers stable releases only. With nix-darwin's Homebrew module:
homebrew.taps = [ "nicolaischmid/tap" ];
homebrew.casks = [ "nicolaischmid/tap/steno" ];
flake.nix installs the released Steno.app unchanged (no rebuild, no re-signing) on
aarch64-darwin.
With nix-darwin, add the flake as an input and put steno.packages.aarch64-darwin.steno
in environment.systemPackages; nix-darwin links Applications/Steno.app into
/Applications/Nix Apps. With home-manager use home.packages and link the app yourself
(home.file into ~/Applications, or the mac-app-util module); home-manager does not
link Applications/ on its own. nix run does not apply, the output is an app bundle
with no bin/.
The app runs from the read-only Nix store, so Sparkle's "Check for Updates…" can download
a new version but cannot install it. Update by bumping release.version and
release.hash at the top of flake.nix (the release workflow prints both in its job
summary) and rebuilding. To silence the scheduled daily check:
defaults write uno.schmid.steno.mac SUEnableAutomaticChecks -bool NO
nix-darwin users who want in-app updates can use the Homebrew cask through
homebrew.casks instead; it installs into /Applications, where Sparkle can write.
flowchart LR
subgraph capture["1 · Capture"]
apps["Zoom · Teams · Meet<br>FaceTime · Continuity call"] -->|Core Audio process tap| them["“them” lane"]
mic["Your microphone"] -->|echo-cancelled| me["“me” lane"]
phone["iPhone recorder"] -.->|local network handover| room["in-person recording"]
end
subgraph process["2 · Process, on your Mac"]
stt["Transcribe<br>Parakeet or Whisper"] --> dia["Diarize and match<br>known voices"] --> llm["LLM cleanup, summary,<br>tasks · text only"]
end
subgraph deliver["3 · Deliver"]
vault["Obsidian vault<br>one folder per meeting"]
end
capture --> process --> deliver
One dated folder per meeting, named after the title. The folder note is what Obsidian opens when you click the folder.
Meetings/
└── 2026-09-24-produktstrategie-90-10-roadmap-fuer-q4/
├── 2026-09-24-produktstrategie-90-10-roadmap-fuer-q4.md # summary, decisions, scratchpad
├── 2026-09-24-produktstrategie-90-10-roadmap-fuer-q4 - Transcript.md
├── 2026-09-24-produktstrategie-90-10-roadmap-fuer-q4 - Tasks.md # Obsidian Tasks syntax
├── transcript.vtt
├── meeting.json
└── audio.m4a # opt-in per meeting
The folder note carries queryable frontmatter and links to the people who were there:
---
title: "Produktstrategie: \"90/10\" & Roadmap für Q4"
date: 2026-09-24T14:00:00
duration: 90
participants:
- "[[Anna Müller]]"
- "Jérôme Dupont"
- "[[Nicolai Schmid]]"
tags:
- "meeting"
- "Kunde-ACME"
source: "mac-call"
template: "default"
language: "de"
---
# Produktstrategie: "90/10" & Roadmap für Q4
2026-09-24 14:00–15:30 · 1 h 30 min · Mac call · [[… - Transcript|Transcript]] · [[… - Tasks|Tasks]]
## Summary
### Executive Summary
- **Fokus**: **Anna Müller** setzt 90 Prozent auf den Kern und 10 auf Experimente.
## Decisions
- 90/10-Aufteilung wird umgesetzt.
Tasks come out ready for the Obsidian Tasks plugin, so they show up in your existing queries next to everything else:
- [ ] Angebot an ACME schicken [[Anna Müller]] ⏫ 📅 2026-10-01
- [ ] Roadmap-Folien aktualisieren [[Nicolai Schmid]] 📅 2026-10-15
Summaries follow one of four built-in templates: Default, Customer Discovery, Daily Standup and Interview. Pick a different one after the fact and re-run the summary without touching the transcript.
Records without a bot Core Audio process taps for the other side, your mic for you. Nobody in the call sees a notetaker, and it works for anything that plays audio on your Mac, including phone calls taken via Continuity and in-person meetings.
Everything on your Mac Transcription, diarization and speaker matching run on-device. The only network traffic Steno generates is transcript text to the LLM endpoint you chose.
Remembers voices Name a speaker once and Steno recognises them next time. Unknown speakers get a ten-second clip to listen to, plus name suggestions from the conversation and the calendar invite.
German, English and Denglish Language is detected per meeting, and an LLM cleanup pass fixes the code-switching, casing and product names every speech model gets wrong.
Knows when a meeting starts A prompt appears when another app opens the microphone. Calendar titles and attendees are filled in from EventKit, no Google Calendar API involved.
Files, not lock-in Markdown, VTT and JSON per meeting. Optional per-person pages linking their meetings. Read, search and automate in your vault with whatever tools and agents you already use.
You decide what to keep Audio retention is a setting: delete right after processing, keep for N days, or keep forever, with a per-meeting override.
Bring your own model Any OpenAI-compatible endpoint works for post-processing, from a hosted API to a model running on the same Mac. Base URL and API key, nothing else.
| Data | Where it goes |
|---|---|
| Meeting audio | Stays on your Mac, in a folder you choose. Deleted per your retention setting. |
| Transcript text | Sent to the LLM endpoint you configure, and only there. |
| Speaker voice embeddings | Stored in the local SQLite database. Never uploaded. |
| Summary, tasks, notes | Written to your vault. The app never runs git or syncs anything itself. |
| Phone recordings | Travel from your iPhone to your Mac over the local network only, TLS with pinned keys. |
There is no Steno server. Disk encryption is FileVault's job.
For meetings away from the Mac there is a deliberately dumb iOS recorder in
mobile/. It records, keeps a local queue, and hands the files to your paired
Mac over the local network when both are on the same Wi-Fi. Pairing is a one-time QR
scan; transport is HTTPS with pinned certificates. Processing happens on the Mac with the
same pipeline as any in-person recording. The phone holds no notes and needs no account.
Steno is scoped on purpose. It does not run on Windows, Linux or Intel Macs. There is no live transcript during the call, no chat over your meetings, no editing of generated text inside the app, no team features, no hosted service and no App Store build. The app is the source of truth for your data; reading, searching and automation happen in your vault.
Swift 6 and SwiftUI on macOS 15+, SQLite via GRDB, FluidAudio and WhisperKit for speech, SpeexDSP for echo cancellation, SwiftNIO for the phone handover, Sparkle for updates. The iOS recorder is an Expo dev-client app.
AGENTS.md conventions for coding agents (CLAUDE.md links here)
Package.swift Swift package: StenoCore, StenoAudio, StenoSpeech, StenoLLM,
StenoAdapters, StenoHandover and the `steno` CLI
apps/macos/ SwiftUI app over the package, xcodegen project, own README
apps/site/ landing page (steno.nicolaischmid.com), Next.js static export in the root pnpm workspace
mobile/ Expo iOS recorder, own pnpm project, own README
.plans/ scope and dated implementation plans
docs/research/ teardown of commercial recorders and the open-source landscape
.github/workflows/ repository, Swift, web, site and mobile CI; macOS release on `v*` tags
swift build && swift test # the package; Apple-only modules need macOS
swift run steno record --help # record from the CLI
swift run steno dev models list # speech and diarization model assets
swift run steno dev bakeoff --help # compare speech engines over a folder
Building the app: apps/macos/README.md. The phone side:
mobile/README.md. Conventions, review priorities and the plan
workflow: AGENTS.md. Everything that is not UI lives in the package, so
the CLI, the macOS app and any future surface share one implementation.
Steno started as an open-source alternative to commercial meeting recorders. Along the way it borrows ideas from anarlog, Parrot and AudioCap, all rebuilt rather than forked. The name is a nod to stenographers and is known to collide with a few commercial products; that is acceptable for a personal open-source project.
MIT, see LICENSE, except where a directory or file carries its own
licence: crates/steno-audio/vendor/speexdsp (BSD),
crates/steno-audio/src/codec/salvage/tables.rs (MPL-2.0, AAC tables copied from the
symphonia-codec-aac crate; the AUR package ships a copy,
packaging/aur/symphonia-aac-tables.rs).