Skip to main content
Glama
README.md
<div align="center">

<img src="icon.png" width="128" alt="Duma icon">

# Duma - Async questions from AI agents to you, via MCP<br>Answer by text or voice

*"Duma" - Hungarian for "talking"*
</div>

Duma is a local macOS app. Agents send questions through MCP, you answer in a native window whenever you get to it, and agents poll back for the response.

## Demo

![Duma demo](static/demo.gif)

## Prerequisites

- macOS (tested on macOS 15+)
- [Homebrew](https://brew.sh)

## Setup

### 1. Install dependencies

```bash
brew install python           # 3.12 or newer
brew install portaudio        # required for audio recording
brew install uv               # Python package manager
```

### 2. Clone and set up the project

```bash
git clone https://github.com/zoltanpetrik/duma.git
cd duma
uv venv                 # creates an isolated Python environment for Duma
uv sync                  # installs all dependencies into that environment
```

Voice transcription requires an OpenAI API key - see [Configuration](#configuration) below. The app works without it; recordings just won't be transcribed.

## Running

```bash
source .venv/bin/activate
python -m duma
```

With debug mode (enables developer tools and verbose logging):

```bash
python -m duma --debug
```

When running from the command line, the menu bar icon and microphone TCC prompt will show `Python` instead of `Duma`. Use the distribution build for full macOS integration.

### Try it out

The app opens empty. To see it in action without setting up MCP, start the app in debug mode (`python -m duma --debug`) and create a test question from another terminal:

```bash
curl -X POST http://localhost:31299/api/questions \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "test-agent",
    "short_description": "Pasta or rice?",
    "question_body": "Should we make pasta or rice tonight?",
    "proposed_answers": ["Pasta", "Rice", "Something else"],
    "high_priority": false
  }'
```

A notification pops up, the question appears in the sidebar, and you can answer it. This endpoint is only available in debug mode - in production, questions come through MCP.

### CLI options

| Option | Default | Description |
|---|---|---|
| `--port` | `31299` | HTTP server port |
| `--debug` | off | Enable pywebview devtools (right-click → Inspect Element) and verbose logging |

## MCP Configuration

Make sure Duma is running before you connect any MCP client.

### Claude Code

Add Duma as a global MCP server so it is available in every project:

```bash
claude mcp add --transport http --scope user duma http://localhost:31299/mcp
```

Then verify that it was added:

```bash
claude mcp list
```

### Encouraging Claude to use Duma

Claude will not proactively use Duma unless you tell it to. Add this to your project's `CLAUDE.md` (or `~/.claude/CLAUDE.md` to apply it globally):

```markdown
## Duma (async questions)

When you encounter a question or decision that doesn't need an immediate answer
(approvals, preferences, non-blocking clarifications), use the Duma MCP tools
instead of asking in the chat. This lets me answer on my own time while you
continue working.

Use agent_id "claude-code" for all Duma calls. Before asking a new question,
call list_my_pending_questions to check if you already have unanswered questions
on the same topic. After asking, continue with other work and poll get_response
later - don't wait for an answer.
```

### Other MCP clients

Add Duma to your MCP client config:

```json
{
  "mcpServers": {
    "duma": {
      "url": "http://localhost:31299/mcp"
    }
  }
}
```

## Distribution build

For proper macOS integration (Dock name, notification identity, microphone permission prompt all showing "Duma" instead of "Python"), build the standalone app:

```bash
./build.sh
open dist/Duma.app
```

This runs PyInstaller and bundles the Python interpreter, dependencies, application code, and static files into a self-contained app at `dist/Duma.app`. The script handles code signing automatically. The app icon lives at `static/icon.icns` (generate one at [icon.kitchen](https://icon.kitchen) if you need to replace it).

The output can also be copied to another Mac and launched directly - no Python, venv, or Homebrew needed on the target machine.

## Configuration

To enable voice transcription, create a config file with your OpenAI API key:

```bash
mkdir -p ~/.duma
cat > ~/.duma/config.json << 'EOF'
{
    "OPENAI_API_KEY": "your-api-key-here"
}
EOF
```

The app works without this - voice recordings are saved but not transcribed. Transcription language (Hungarian/English) can be switched in the app via the toggle next to the record button.

## Development

See [DOCS.md](docs/DOCS.md) and [SPECS.md](docs/SPECS.md) for the full picture.

### Tests

```bash
uv sync --group test
.venv/bin/python -m pytest
```

66 tests covering the database, service, REST API, and transcription layers. macOS-native integration (menu bar, notifications, audio recording) is tested manually - see the QA checklist in [SPECS.md](docs/SPECS.md).

## Data

All Duma data stays local:

- Configuration: `~/.duma/config.json`
- Database: `~/.duma/duma.db`
- Audio recordings: `~/.duma/audio/`
- Logs: `~/.duma/duma.log`

Maintenance

ActivityInactive
ResponsivenessNo issues