Skip to content

harshitsinghbhandari/donna

Repository files navigation

Donna

Python 3.11+ macOS

Local-first macOS AI assistant with voice, screen, text, memory, and Discord integrations.

Donna is an ambient assistant that runs from one command, stores its working state on your Mac, and only reaches out when a feature needs an external service: Discord for messages, Gemini for the brain, and optional Composio or Ollama integrations for tools and local model work.

Visual proof is the one missing repo asset: add a 20-30 second GIF here showing donna run, the menubar, a voice turn, or a Discord DM exchange.

Why

I wanted an assistant that lives close to the machine instead of pretending the cloud owns all context. Donna keeps config, secrets, transcripts, history, and memory under ~/.donna/, uses native macOS capabilities where they fit, and exposes the same brain through voice, screen, text, and scheduled briefing workflows.

The thesis is simple: personal AI should be useful across surfaces, but the durable context should stay local by default.

What It Does

Donna ships four connected modes:

  • Briefing: pulls Discord #ideas into structured briefings on a schedule, then posts to Discord or email.
  • Voice: press Option-Space, speak, and hear a reply. STT runs locally with Whisper, TTS uses macOS say, and Gemini handles reasoning.
  • Screen: passively captures, deduplicates, OCRs, describes, redacts, stores, and batch-summarizes screen context.
  • Text: DM Donna's Discord bot from desktop or phone. Replies are markdown-friendly, owner-allowlisted, chunked for Discord, and backed by persistent SQLite memory.

Shared capabilities include a skill registry, Composio dynamic tool routing, local summarization and transformation through Ollama, context files, launchd automation, macOS notifications, and runtime health from a menubar icon.

See CAPABILITIES.md for the shipped feature matrix and current rough edges.

How It Works

flowchart LR
    User[User] --> Surface[macOS surfaces]
    Surface --> Voice[Voice mode]
    Surface --> Screen[Screen mode]
    Surface --> Text[Text mode]
    Surface --> Briefing[Briefing mode]

    Voice --> Brain[Shared brain loop]
    Text --> Brain
    Briefing --> Brain
    Screen --> Store[(Local SQLite + transcripts)]
    Screen --> Brain

    Brain --> Skills[Skill registry]
    Brain --> Gemini[Gemini API]
    Brain --> Memory[(SQLite + FTS5 memory)]

    Skills --> Native[Native skills]
    Skills --> Composio[Composio tools]
    Skills --> Ollama[Ollama local helpers]

    Briefing --> Discord[Discord]
    Text --> Discord
    Screen --> Discord
    Brain --> History[(~/.donna history)]
Loading

Layer map:

surface/   pynput hotkey + rumps menubar
voice/     sounddevice mic capture, faster-whisper STT, macOS say TTS
screen/    capture + Apple Vision OCR + Ollama describe + cleanup + summarize
text/      discord.py DM listener + shared brain turns + Discord chunking
brain/     provider protocol, Gemini provider, conversation, dispatcher
skills/    auto-discovering registry + native skills + Composio adapter
memory/    SQLite + FTS5 storage and retrieval
runtime/   DonnaHost orchestration and per-mode health

Quickstart

Requires macOS and Python 3.11+.

./setup.sh

This creates a venv at ~/.donna/venv/, installs Donna, and places a wrapper at /opt/homebrew/bin/donna so it works from any directory.

For development:

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Then configure and verify:

donna setup
donna doctor

donna setup asks for your Discord bot token, Gemini API key, channel IDs, output choices, briefing interval, and optional email credentials. It creates ~/.donna/.env, ~/.donna/config.toml, and context templates.

Full setup for every mode is in SETUP.md.

Common Commands

donna run                                # all enabled modes
donna run --voice --no-screen --no-text  # voice only
donna run --text --no-voice --no-screen  # text only
donna brief --dry-run                    # preview a briefing without posting
donna brief                              # run a briefing and dispatch it
donna brief --since 24h                  # review a specific time window
donna screen summarize                   # batch summarize unsummarized screen transcripts
donna status                             # show config and state summary
donna doctor                             # diagnose setup, Discord, and Gemini

Daemon commands:

donna daemon install        # install and start the launchd daemon
donna daemon status         # show if running, PID, pending jobs
donna daemon logs           # tail the daemon log
donna daemon uninstall      # stop and remove the daemon

History and memory:

donna history               # last 10 briefing runs
donna history --all         # all briefing runs
donna raw 1                 # raw messages + briefing for the latest run
donna memory list           # inspect text-mode memory
donna memory search "query" # search saved memories

Local State

Donna keeps its personal runtime data under ~/.donna/:

~/.donna/
  .env                         # secrets: Discord, Gemini, email
  config.toml                  # mode configuration
  context/*.md                 # persona, work, goals, style, interests
  history/                     # briefing provenance
  voice.log                    # runtime log
  screen.db                    # screen transcripts and summaries
  screen/shots/                # in-flight PNGs, cleaned after processing
  screen/transcripts/          # retained screen transcript markdown
  memory.db                    # text-mode memory
  composio_skills_cache.json   # cached tool catalog and schemas

Nothing leaves the machine except outbound calls required by the mode you enabled.

Mode Notes

Briefing

Donna reads a Discord #ideas channel, turns new messages into a structured briefing, and posts to #briefings or email. It supports dry runs, custom time windows, saved history, raw replay, launchd scheduling, and macOS notifications for urgent items.

Personal context comes from ~/.donna/context/*.md:

  • persona.md: who you are, background, how you think
  • work.md: current projects and recent shipped work
  • interests.md: recurring themes
  • goals.md: this week, month, and quarter
  • style.md: briefing tone and notification sensitivity

Run donna context to see token counts per file.

Voice

Voice mode gives Donna a menubar-hosted push-to-talk surface. Hold Option-Space, speak, release, and Donna runs the shared brain loop with local STT and macOS TTS.

The voice brain can answer general questions, open apps and URLs, call registered skills, route Composio tools, summarize or transform local files with Ollama helpers, and use your configured personal context.

Screen

Screen mode captures on an interval, filters sensitive windows before capture, performs Apple Vision OCR, redacts likely secrets after OCR, asks a local Ollama vision model for scene descriptions, stores transcripts in SQLite, and summarizes unsummarized batches on demand.

The summarizer can post batches to Discord and marks each transcript as summarized, so retries only pick up remaining work.

Text

Text mode lets you DM Donna's Discord bot. It uses the same brain and skill registry as voice mode, but replies in Discord-friendly markdown and remembers explicit facts through SQLite + FTS5.

Only the configured owner ID can talk to the bot. Other users, bot messages, non-DM channels, empty messages, and unsupported attachments are dropped or handled cleanly.

Tool Catalog

Donna keeps the active tool catalog small so model calls stay useful:

  1. Heavy-use tools: frequently used Composio slugs, such as Gmail send and read actions, are registered directly.
  2. Composio meta-tools: composio_search_tools, composio_execute, and composio_get_tool_schema let the brain find and call less common tools dynamically.
  3. Native and memory skills: ask, open_app, self_aware, read_file, local_summarize, local_transform, memory_save, and memory_search.

Add a new native skill by dropping a file in src/donna/skills/<domain>/<name>.py that subclasses Skill. The registry's discover() method picks it up automatically.

Troubleshooting

Invalid Discord bot token: Check DISCORD_BOT_TOKEN in ~/.donna/.env.

Donna cannot access this channel: Check bot permissions and channel IDs.

Gemini rejected the request: Check GEMINI_API_KEY, the configured model, and billing in Google AI Studio.

No new ideas to brief: No messages were found after the saved watermark. Use donna brief --since 24h --dry-run to review a time window without touching state.

Bot drafts an email but says "I can't send drafts": Composio toolkits over 30 tools used to silently truncate the catalog, dropping gmail_send_email and gmail_send_draft. Reinstall if you're on an older build.

Bot drafted or created something but failed with 403 PERMISSION_DENIED: Composio's OAuth grant for that toolkit does not include the scope needed for the action. Re-link the toolkit with composio link gmail and grant the additional permission in the browser flow.

See SETUP.md#troubleshooting for the full list.

Development

pytest tests/ -v
ruff check src/ tests/
ruff format src/ tests/

Repository Settings Status

Already applied on GitHub:

  • Description: Local-first macOS AI assistant with voice, screen, text, memory, and Discord integrations.
  • Topics: ai-assistant, agents, macos, python, local-first, ocr, discord, sqlite, llm, automation

Remaining public-facing assets:

  • Homepage: project page or demo video URL
  • README visual: replace the placeholder note near the top with a short GIF or screenshot

About

Local-first macOS AI assistant with voice, screen, text, memory, and Discord integrations.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors