Skip to main content

huske

CI License: MIT

huske — Norwegian for "to remember"

A native macOS app backed by a headless engine that continuously records your microphone plus your computer's system audio, and transcribes the audio locally with Parakeet on Apple Silicon (MLX) — producing a day-organized, LLM-friendly knowledge base of everything that was said on your machine throughout the day.

Point Claude Code (or any other LLM agent) at ~/huske/transcripts/ and ask it about your day.

~/huske/transcripts/
├── 2026-05-07/
│   ├── 091500_8a3f2c19_001.md
│   ├── 093000_8a3f2c19_002.md
│   └── 094500_8a3f2c19_003.md
└── README.md

Features

  • Continuous capture — mic (sounddevice) + system audio (Core Audio process tap on macOS 14.4+, ScreenCaptureKit fallback on older macOS), source-tagged and gapless at chunk boundaries.
  • No drivers, no Audio MIDI Setup — system audio comes through Apple's built-in capture APIs. Grant the macOS audio/screen capture permission once.
  • Local transcription — Parakeet (parakeet-tdt-0.6b-v3) on the Apple Silicon GPU via MLX. It is multilingual (~25 languages) and, being a transducer, emits nothing on silence instead of hallucinating repeated filler the way Whisper does. Audio never leaves your machine. Parakeet infers the language per decode window and cannot be told which one, so if you speak a non-English language mixed with English jargon and need the transcript pinned to one language, use the Whisper engine, whose decoder takes a language token: --asr-engine whisper --model large-v3-turbo --language pt.
  • Speech-gated segmentation — files split on real pauses in speech, not a fixed clock: a chunk opens when speech starts and closes after a pause (--silence-split, default 60 s) or at the --chunk-minutes cap (default 30 min). Quiet stretches produce no file, and a conversation isn't cut mid-sentence at an arbitrary tick. --no-speech-gated restores fixed-interval rotation.
  • Speaker-bleed removal — when you record mic + system on speakers (no headphones), the system audio bleeds into the mic and would be transcribed twice. huske handles it in two stages: coherence-based echo suppression attenuates the bleed in the mic audio before transcription (--echo-cancel, on by default; self-gating — no effect with headphones, and it can't touch your own voice), and a transcript-level dedup then removes any residual mic copy of a system line, including partial fragments (--echo-dedup drop|annotate|off). (True sample-precise cancellation isn't possible because the mic and system are captured on independent clocks — see the PR notes.)
  • Resilient — graceful stop finalizes the partial chunk; SIGKILL + restart auto-recovers orphaned audio.
  • Native macOS app — huske's face: live level meters, start/stop/pause, a ⌘K command palette, mid-session toggles, a transcript browser with search, a Doctor pane, an engine-validated settings editor, and open-at-login + record-on-open switches, plus a menu bar extra. It also attaches to sessions started from the terminal or at login. Built from source in macos/; see docs/macos-app.md.
  • Headless engine — huske run records with no UI chrome: plain progress lines on stdout and a macOS menu bar item for pause/screenshots/stop. Ideal under a LaunchAgent or over SSH. (The old Rich terminal panel was retired in favor of the app — see docs/adr/0007-app-first-retire-the-tui.md.)
  • LLM-ready output — every transcript is a single Markdown file with full YAML frontmatter; the directory layout is documented in ~/huske/transcripts/README.md (auto-generated).
  • Private GitHub sync (opt-in) — Huske.app publishes each finished transcript to a private Git repository through your existing SSH/Git credentials. Git commits are the durable retry queue; Huske stores no cloud token and never syncs audio, screenshots, logs, or config.
  • Always-on MCP as a separate service — services/huske_mcp runs on a Linux/VPS, pulls the repository, incrementally indexes it, and serves agents while the Mac sleeps. The default profile is designed for a 512 MB VPS; semantic hybrid search is an explicit larger-memory option.
  • LLM distillation into statements (opt-in) — distil each transcript into compact, self-contained claims with a local MLX model or Ollama. Derived sidecars are on-device and never required by the remote retrieval index.
  • Optional periodic screenshots — opt in with --screenshots to also capture a JPEG of every attached display every 60 s (compressed for LLM input), stored under ~/huske/screenshots/YYYY-MM-DD/<session>/HHMMSS_dN.jpg for downstream multimodal LLM use. Off by default; see Periodic screenshots.

Requirements

  • macOS 13 (Ventura) or newer. macOS 14.4+ is recommended for system audio capture that keeps working while another app is sharing your screen. Apple Silicon is the primary target.
  • Python 3.11, 3.12, 3.13, or 3.14.

Quickstart

# 1. Install
uv tool install huske

# 2. Validate setup (will prompt for macOS capture permission on first run)
huske doctor

# 3. Record (Ctrl+C to stop)
huske run

# 4. Reclaim orphans from a prior crash without recording
huske recover

Other install options:

# Alternative Python tool installer:
pipx install huske

# macOS Apple Silicon with Homebrew:
brew tap tiagomoraes/huske
brew install huske

On macOS 14.4+, Huske uses a Core Audio process tap for system audio so Google Meet, Zoom, and similar screen sharing do not interrupt capture. macOS may prompt for Audio Capture or a screen-recording-adjacent permission for your Python interpreter or launcher. On older macOS versions, or when --system-audio-backend sck is set, Huske falls back to ScreenCaptureKit, which requires Screen Recording permission and can be interrupted by another app's screen share. Run huske doctor --system-audio-backend tap if the system level meter goes silent during screen sharing.

Runtime controls live in the app and the menu bar:

  • Huske.app — pause/resume, screenshots, distillation, and microphone switching from the Record pane — or from anywhere via the ⌘K command palette.
  • Menu bar — terminal and LaunchAgent sessions get a huske menu bar item with pause/resume, screenshots, distillation, and stop.
  • Ctrl+C — graceful stop for terminal sessions (finalizes the current chunk and drains pending transcriptions).

Pausing finalizes the current partial chunk and stops writing audio until you resume. Toggling screenshots takes effect immediately, using the configured screenshots directory and interval. Toggling distillation flips it on or off for the running session: turning it on checks that the local LLM daemon and model are ready before it starts (and warns with a fix-it hint if they are not). On macOS the same actions are available from the menu-bar dropdown. The toggle is session-only — set distill_enabled in config to make it the default.

For prerelease builds or exact GitHub tags, install directly from the repository:

uv tool install "git+https://github.com/tiagomoraes/huske.git@v0.13.0"

See quickstart.md for the full setup.

Run on login (macOS)

The easiest way is in Huske.app → Configuration → This app: switch on Open Huske at login and Start recording when Huske opens — your Mac records from the moment you sign in, with the app as the UI.

Prefer no app at all? huske autostart install registers a per-user LaunchAgent that runs a headless huske run automatically every time you log in (the menu bar item is then the only UI).

# Install — writes ~/Library/LaunchAgents/me.huske.plist and loads it now.
huske autostart install

# Optional: pass a config file or non-default log level.
huske autostart install --config ~/.config/huske/config.toml --log-level DEBUG

# Show current state (installed, loaded, pid, last exit code).
huske autostart status

# Manually start/stop without uninstalling (repeated stop is a no-op).
huske autostart start
huske autostart stop

# Remove entirely.
huske autostart uninstall

Restart policy is "restart on crash only" by default (KeepAlive={SuccessfulExit:false}): if you huske autostart stop or huske exits cleanly, it stays stopped until next login. Pass --no-keep-alive to disable auto-restart on crash too.

Permissions. The first time the agent records, macOS will prompt for Microphone and the relevant audio/screen capture permission for the resolved huske binary (or its Python interpreter). Approve them in System Settings → Privacy & Security. If the prompts don't appear after login, run huske autostart start once from the terminal so they fire while you're present.

Logs. The agent is headless; stdout and stderr are appended to:

~/Library/Logs/huske/agent.out.log
~/Library/Logs/huske/agent.err.log

Tail those if you suspect the agent isn't recording. huske doctor also reports the agent's state — installed, loaded, pid, and the error-log path if it recently crashed — so you can check on it without a separate command.

huske autostart is macOS-only (it uses launchd); the commands exit with a friendly error on other systems.

Update notifications

On startup, huske checks PyPI at most once every 24 hours and prints an "update available" banner with the right upgrade command for your install method (uv tool upgrade huske, pipx upgrade huske, or brew upgrade huske). The check runs in a background thread, is silent on network errors, on non-TTY stderr, and for editable installs. Disable it with:

export HUSKE_NO_UPDATE_CHECK=1

Periodic screenshots (opt-in)

huske run --screenshots enables a background thread that captures a JPEG of every attached display every 60 seconds (configurable). Screenshots are written to:

~/huske/screenshots/YYYY-MM-DD/<session_id>/HHMMSS_dN.jpg

…where dN is the display index (d1 is the main display). Filenames are timestamped so a downstream multimodal LLM can correlate each screenshot with that day's transcripts.

Capture uses macOS's built-in screencapture, so no extra dependency is needed. It uses Screen Recording permission; if system audio is using the Core Audio tap, macOS may prompt for this separately when screenshots are first enabled.

Each capture is then shrunk in place with macOS's built-in sips: downscaled so its long edge is at most 1568 px (the resolution Claude's vision API targets; never upscaled) and re-encoded at JPEG quality 60 — small to store and ideal as LLM input. Tune with --screenshot-max-dimension (0 disables resize) and --screenshot-quality; if sips isn't on the PATH the full-size capture is kept.

Flags:

huske run --screenshots                       # opt in
huske run --screenshots --screenshot-interval 30
huske run --screenshots --screenshot-quality 50 --screenshot-max-dimension 1024
huske run --screenshots --screenshots-root ~/another/path

The screenshot interval must be at least 1 second.

Privacy. Screenshots can capture passwords, private chats, financial details, and anything else on screen. They're stored unencrypted on disk and read-accessible to any process running as your user. Treat ~/huske/screenshots/ exactly like the audio and transcript directories: never commit it, share with care, and review the Privacy and consent section before enabling.

Sync transcripts and query them from agents (opt-in)

The recording app does not host MCP. Open Cloud sync in Huske.app, create a private GitHub repository, paste its SSH URL, and press Sync now. After the first push succeeds, enable automatic sync.

Terminal equivalent:

huske config set sync_remote git@github.com:you/huske-transcripts.git
huske config set sync_enabled true
huske sync

Huske publishes only canonical transcript Markdown under transcripts/YYYY-MM-DD/*.md. Git uses your existing SSH agent or credential helper; Huske stores no GitHub token. Audio, screenshots, logs, config, and credentials are never copied.

Run the independent services/huske_mcp package on an always-on Linux/VPS host. It pulls the private repository, incrementally indexes it into SQLite, and serves a permanent authenticated Streamable-HTTP MCP endpoint with overview, recap, search, fetch, and sync_status.

The default tiny profile is designed for 1 vCPU / 512 MB: one process, one poll thread, FTS5, an 8 MB SQLite cache, and no resident model. The optional semantic profile adds real hybrid Model2Vec retrieval and needs more memory (at least 1 GB for the default multilingual model).

Polling is the consistency mechanism; a signed GitHub webhook can wake it early. This heals missed webhooks and restarts without a second data plane. Full setup: docs/server.md. Client wiring: docs/integrations.md. Decision record: ADR 0009.

Distil transcripts into statements (opt-in)

Huske can distil each transcript into compact, self-contained statement sidecars using a local MLX model or Ollama. These are derived and optional; the VPS service builds retrieval from canonical transcript Markdown and never depends on them.

huske distill

To keep sidecars fresh automatically:

distill_enabled = true
distill_model = "mlx-community/Qwen3.5-0.8B-4bit"

Distillation runs off the recording hot path and failures never block recording or cloud sync. See docs/distillation.md.

Privacy and consent

huske is local-first: audio capture and transcription run on your machine, and the app writes transcripts to your configured filesystem path. That does not make the data low-risk. Recordings, transcripts, logs, filenames, and device metadata can contain private or legally sensitive information.

  • Get consent before recording other people or regulated conversations.
  • Do not commit generated audio, transcripts, logs, local configs, model caches, or screenshots containing private content.
  • If you enable cloud sync (sync_enabled), plaintext transcripts are copied to the private Git repository you configured. Restrict repository access, enable strong GitHub account security, and treat its history as sensitive.
  • The VPS replica also holds plaintext transcript history. Keep huske-mcp on loopback or a private overlay, terminate TLS at the proxy, require its bearer token, and enable disk encryption on the host.
  • If you run huske export and sync that folder to a third-party cloud (Drive, Dropbox, iCloud), plaintext transcripts are stored there under that provider's retention and scanning policy. Prefer --statements-only if you do.
  • If you enable distillation (distill_enabled), transcript text is sent to the configured local model backend. The default MLX backend runs as a child process on your Mac; Ollama is an optional loopback backend. Pointing an endpoint at a remote daemon changes that privacy boundary.
  • The --screenshots flag captures everything visible on every attached display every 60 s — including any password manager popovers, banking tabs, or private DMs that happen to be open. Leave it off unless you've consciously decided you want this in the on-disk record.
  • Redact huske doctor output before sharing it publicly.
  • Report security or privacy vulnerabilities privately through SECURITY.md.

Documentation

Community

License

huske is released under the MIT License. Third-party notices are in THIRD_PARTY_NOTICES.md.

Metadata

Release files for huske 0.13.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for huske 0.13.0
File Size Uploaded
huske-0.13.0.tar.gz 295.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for huske 0.13.0
File Interpreter ABI Platform
huske-0.13.0-py3-none-any.whl Python 3 none any Details

Total release size: 465.2 kB

Release files / huske-0.13.0.tar.gz

Download URL huske-0.13.0.tar.gz
Size 295.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5769dff05ea3f9e833c5e5e6069d93e58194148319ed9b6430604c36d731f25f
BLAKE2b-256 checksum
How to use checksums
33bf3409555013a8434fb395b31bec210a5302e385a0a12b1b560bcda2d197e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 31, 2026.

Transparency log

Release files / huske-0.13.0-py3-none-any.whl

Download URL huske-0.13.0-py3-none-any.whl
Size 169.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3139b7150ef83255611449775338a12b4dec0fa1f375e704d09e881c96bb1d65
BLAKE2b-256 checksum
How to use checksums
0723ac708f683dbe69dfeaa18fb3d84e14e2bfe485e13af9d9f7059db9c99e22
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 31, 2026.

Transparency log

Release history Release notifications | RSS feed

0.14.0

2 release files

This release

0.13.0 This release

2 release files

0.12.0

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page