Metadata-Version: 2.4
Name: otterai-cli
Version: 0.1.3
Summary: Unofficial Otter.ai CLI — list, search, download, and manage meeting transcripts. Built for developers, scripts, and AI agents.
Project-URL: Homepage, https://github.com/erickhchan/otterai-cli
Project-URL: Repository, https://github.com/erickhchan/otterai-cli
Project-URL: Issues, https://github.com/erickhchan/otterai-cli/issues
Project-URL: Changelog, https://github.com/erickhchan/otterai-cli/releases
Project-URL: Documentation, https://github.com/erickhchan/otterai-cli#readme
Author-email: Eric Chan <eric.kahei.chan@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agent,automation,cli,meeting,meeting-notes,meeting-transcription,otter,otter.ai,speech-to-text,transcript
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications
Classifier: Topic :: Office/Business
Classifier: Topic :: Text Processing
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: click>=8.0
Requires-Dist: keyring>=23.0
Requires-Dist: requests
Requires-Dist: requests-toolbelt
Provides-Extra: dev
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: responses; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Description-Content-Type: text/markdown

# otterai-cli — Otter.ai CLI & AI Agent Tool

[![PyPI](https://img.shields.io/pypi/v/otterai-cli)](https://pypi.org/project/otterai-cli/)
[![Python](https://img.shields.io/pypi/pyversions/otterai-cli)](https://pypi.org/project/otterai-cli/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

A command-line interface for [Otter.ai](https://otter.ai) to list, search, download, and manage your meeting transcripts and recordings. Built for developers, scripts, and AI agents like Claude, ChatGPT, and Cursor.

> **Note:** This project is not affiliated with or endorsed by Otter.ai / Aisense Inc.

## Features

- **List, search, and filter** meeting transcripts by date, folder, or keyword
- **Download transcripts** as txt, pdf, md, docx, or srt
- **Download meeting audio** as mp3
- **Export markdown** with configurable YAML frontmatter
- **Upload audio files** for transcription
- **Manage speakers, folders, and groups** programmatically
- **JSON output** for scripting, piping, and AI agent consumption
- **Secure credential storage** via OS keychain (macOS Keychain, Windows Credential Locker, etc.)

## AI Agent & LLM Usage

This CLI is designed to be used by AI agents (Claude, GPT, Cursor, Windsurf, etc.) as a tool for accessing Otter.ai meeting data.

### Quick Reference

| Task | Command | Output |
|------|---------|--------|
| List recent meetings | `otter speeches list --days 7 --json` | JSON array of speech objects |
| Get full transcript | `otter speeches get OTID --json` | Speech + transcript segments |
| Download as markdown | `otter speeches download OTID -f md` | `.md` file saved to disk |
| Download as text | `otter speeches download OTID -f txt` | `.txt` file saved to disk |
| Download audio | `otter speeches download OTID -f mp3` | `.mp3` file saved to disk |
| Search in meeting | `otter speeches search "query" OTID` | Matching transcript segments |
| List folders | `otter folders list --json` | JSON array of folder objects |
| List speakers | `otter speakers list --json` | JSON array of speaker objects |

Agents can:

```bash
# List recent meetings (JSON for easy parsing)
otter speeches list --days 7 --json

# Search within a specific meeting transcript
otter speeches search "action items" SPEECH_ID

# Download a transcript as markdown
otter speeches download SPEECH_ID --format md

# Get full speech details and transcript
otter speeches get SPEECH_ID --json

# List all folders and speakers
otter folders list --json
otter speakers list --json
```

All commands support `--json` for structured, machine-readable output that agents can parse directly.

### JSON Output Schema

`otter speeches list --json` returns:

```json
{
  "speeches": [
    {
      "otid": "jqb7OHo6mrHtCuMkyLN0nUS8mxY",
      "speech_id": "22WB27HAEBEJYFCA",
      "title": "Weekly Standup",
      "created_at": "2025-02-20T10:00:00Z",
      "summary": "Discussed sprint progress and blockers...",
      "folder": "Work",
      "folder_id": "12345"
    }
  ]
}
```

`otter speeches get SPEECH_ID --json` returns the full speech object including transcript segments:

```json
{
  "speech": {
    "otid": "jqb7OHo6mrHtCuMkyLN0nUS8mxY",
    "title": "Weekly Standup",
    "summary": "Discussed sprint progress and blockers...",
    "transcripts": [
      {
        "speaker": "Alice",
        "text": "Let's go over the sprint updates.",
        "start_offset": 0,
        "end_offset": 4500
      }
    ]
  }
}
```

On error, the CLI exits with code `1` and prints a message to stderr:

```
Error: Authentication required. Run 'otter login' or set OTTERAI_USERNAME and OTTERAI_PASSWORD.
```

### Agent Workflow Example

Find last week's standup, download its transcript as markdown:

```bash
# Step 1: List recent meetings as JSON, filter by title
OTID=$(otter speeches list --days 7 --json | jq -r '.speeches[] | select(.title | test("standup"; "i")) | .otid' | head -1)

# Step 2: Download the transcript
otter speeches download "$OTID" --format md --output standup.md

# Step 3: Or get full transcript data for further processing
otter speeches get "$OTID" --json | jq '.transcripts[] | .speaker + ": " + .text'
```

### Agent Skill

This project includes an [Agent Skill](https://agentskills.io) at [`skills/otterai-cli/`](skills/otterai-cli/SKILL.md) — a portable skill file that compatible agents (Claude Code, Cursor, Copilot, Gemini CLI, etc.) can use to learn this CLI's commands automatically. Copy the `skills/otterai-cli/` directory into your agent's skills folder to give it full Otter.ai access.

### Authentication for Automated Environments

For CI, scripts, or AI agents, use environment variables instead of interactive login:

```bash
export OTTERAI_USERNAME="you@example.com"
export OTTERAI_PASSWORD="your-password"
otter speeches list --json  # no login prompt needed
```

## Requirements

- Python 3.10+

## Installation

```bash
uv tool install otterai-cli
```

This makes the `otter` command available globally.

To update to the latest version:

```bash
uv tool upgrade otterai-cli
```

Or run directly without installing:

```bash
uvx --from otterai-cli otter --help
```

## Setup

```bash
otter login
```

Credentials are stored in your OS keychain (macOS Keychain, Windows Credential Locker, etc.) via [keyring](https://pypi.org/project/keyring/), with `~/.otterai/config.json` as fallback.

You can also use environment variables (`OTTERAI_USERNAME`, `OTTERAI_PASSWORD`), which take highest precedence.

### Auth commands

```bash
otter user      # check current user
otter logout    # remove saved credentials
```

## Command Reference

| Command | Flags | Description |
|---------|-------|-------------|
| `otter login` | | Interactive login, saves credentials to keychain |
| `otter logout` | | Remove saved credentials |
| `otter user` | | Show current authenticated user |
| `otter speeches list` | `--days N`, `--folder NAME`, `--page-size N`, `--source owned\|shared`, `--json` | List speeches |
| `otter speeches get OTID` | `--json` | Get speech details + full transcript |
| `otter speeches download OTID` | `--format txt\|pdf\|md\|docx\|srt\|mp3`, `--output NAME`, `--frontmatter-fields FIELDS` | Download transcript or audio |
| `otter speeches search QUERY OTID` | `--json` | Search within a speech transcript |
| `otter speeches upload FILE` | | Upload audio file for transcription |
| `otter speeches trash OTID` | | Move speech to trash |
| `otter speeches rename OTID TITLE` | | Rename a speech |
| `otter speeches move OTID...` | `--folder NAME`, `--create` | Move speeches to a folder |
| `otter speakers list` | `--json` | List all speakers |
| `otter speakers create NAME` | | Create a new speaker |
| `otter speakers tag OTID SPEAKER_ID` | `--all` | Tag speaker on transcript segments |
| `otter folders list` | `--json` | List all folders |
| `otter folders create NAME` | | Create a folder |
| `otter folders rename ID NAME` | | Rename a folder |
| `otter groups list` | `--json` | List all groups |
| `otter config show` | | Show current config |
| `otter config clear` | | Clear saved config |

## Usage

```bash
otter speeches list                          # list all speeches
otter speeches list --days 7                 # last 7 days
otter speeches list --folder "Work"          # by folder name
otter speeches get SPEECH_ID                 # get speech details + transcript
otter speeches download SPEECH_ID -f txt     # download as txt, pdf, mp3, docx, srt, or md
otter speeches search "keyword" SPEECH_ID    # search within a speech
otter speakers list                          # list all speakers
otter folders list                           # list all folders
```

Run `otter --help` or `otter <command> --help` for more options.

### Important: Speech IDs (otid vs speech_id)

Otter.ai speeches have two identifiers:
- **`speech_id`** (e.g. `22WB27HAEBEJYFCA`) -- internal ID, does **NOT** work with API endpoints
- **`otid`** (e.g. `jqb7OHo6mrHtCuMkyLN0nUS8mxY`) -- the ID used in all API calls

All CLI commands that accept a `SPEECH_ID` argument expect the **otid** value. Use `otter speeches list` to find otids, or `otter speeches list --json | jq '.speeches[].otid'` for just the IDs.

### Speeches

```bash
# List all speeches
otter speeches list

# List with options
otter speeches list --page-size 10 --source owned

# List speeches from the last N days
otter speeches list --days 2

# List speeches in a specific folder (by name or ID)
otter speeches list --folder "CoverNode"

# Get a specific speech
otter speeches get SPEECH_ID

# Search within a speech
otter speeches search "search query" SPEECH_ID

# Download a speech (formats: txt, pdf, mp3, docx, srt, md)
otter speeches download SPEECH_ID --format txt

# Download as markdown (generated locally from transcript data)
otter speeches download SPEECH_ID --format md
otter speeches download SPEECH_ID --format md --output meeting-notes
otter speeches download SPEECH_ID --format md --frontmatter-fields "title,summary,speakers,start_time,end_time,duration_seconds,source,speech_id,folder,folder_id"

# Upload an audio file
otter speeches upload recording.mp4

# Move to trash
otter speeches trash SPEECH_ID

# Rename a speech
otter speeches rename SPEECH_ID "New Title"

# Move speeches to a folder (by name or ID)
otter speeches move SPEECH_ID --folder "CoverNode"
otter speeches move ID1 ID2 ID3 --folder "CoverNode"

# Move to a new folder (auto-create if it doesn't exist)
otter speeches move SPEECH_ID --folder "New Folder" --create
```

#### Markdown frontmatter (`--format md`)

Markdown export includes YAML frontmatter, configurable per download:

```bash
# Use defaults
otter speeches download SPEECH_ID --format md

# Pick exact fields (in your own order)
otter speeches download SPEECH_ID --format md --frontmatter-fields "title,speech_id,summary"

# Disable all frontmatter fields
otter speeches download SPEECH_ID --format md --frontmatter-fields none
```

Default frontmatter fields (in order):
1. `title`
2. `summary`
3. `speakers`
4. `start_time`
5. `end_time`
6. `duration_seconds`
7. `source`
8. `speech_id`
9. `folder`
10. `folder_id`

Available frontmatter fields for `--frontmatter-fields`:
- `title`
- `summary`
- `speakers`
- `start_time`
- `end_time`
- `duration_seconds`
- `source`
- `speech_id`
- `folder`
- `folder_id`
- `otid`
- `created_at`
- `transcript_updated_at`
- `language`
- `transcript_count`
- `process_status`

Notes:
- `--frontmatter-fields` is valid only with `--format md`.
- `speech_id` in frontmatter is the Otter internal `speech_id`; command argument `SPEECH_ID` still expects the `otid`.

### Speakers

```bash
# List all speakers
otter speakers list

# Create a new speaker
otter speakers create "Speaker Name"

# Tag a speaker on transcript segments
otter speakers tag SPEECH_ID SPEAKER_ID
otter speakers tag SPEECH_ID SPEAKER_ID --all
```

### Folders and Groups

```bash
# List folders
otter folders list

# Create a folder
otter folders create "My Folder"

# Rename a folder
otter folders rename FOLDER_ID "New Name"

# List groups
otter groups list
```

### Configuration

```bash
# Show current config
otter config show

# Clear saved config
otter config clear
```

### JSON Output

Most commands support `--json` flag for machine-readable output:

```bash
otter speeches list --json
otter speakers list --json
```

## Error Handling

The CLI returns exit code `0` on success and `1` on any error. Common errors:

| Error | Cause | Fix |
|-------|-------|-----|
| `Authentication required` | No credentials / expired session | Run `otter login` or set `OTTERAI_USERNAME` + `OTTERAI_PASSWORD` env vars |
| `Speech not found` | Invalid `otid` | Use `otter speeches list --json` to get valid otids |
| `Rate limit exceeded` | Too many API requests | Wait a few seconds and retry |

## FAQ

### How do I bulk export all my Otter.ai transcripts?

```bash
otter speeches list --json | jq -r '.speeches[].otid' | while read otid; do
  otter speeches download "$otid" --format md
done
```

### How do I download Otter.ai meeting notes as markdown?

```bash
otter speeches download SPEECH_ID --format md
```

This generates a markdown file with YAML frontmatter (title, summary, speakers, timestamps). See [Markdown frontmatter](#markdown-frontmatter---format-md) for customization.

### Can AI agents like Claude or ChatGPT use this tool?

Yes. Install the CLI, set `OTTERAI_USERNAME` and `OTTERAI_PASSWORD` environment variables, and agents can use all commands with `--json` for structured output. See [AI Agent & LLM Usage](#ai-agent--llm-usage).

### Is there an Agent Skill for this CLI?

Yes. The [`skills/otterai-cli/`](skills/otterai-cli/SKILL.md) directory contains an [Agent Skill](https://agentskills.io) compatible with Claude Code, Cursor, Copilot, Gemini CLI, and other supporting agents. Copy it into your agent's skills directory and the agent will automatically know how to use all `otter` commands.

## Use Cases

- **Bulk export / backup** — download all your Otter.ai transcripts programmatically
- **Automate meeting workflows** — pipe transcript data into scripts or cron jobs
- **AI agent integration** — let Claude, GPT, or other LLM agents access your meeting notes
- **Search across meetings** — find specific discussions without opening the Otter.ai UI
- **Meeting note pipelines** — download as markdown, process with other tools
- **Transcript archival** — export meetings before they expire or for compliance

## Alternatives

| Tool | Type | Notes |
|------|------|-------|
| [Otter.ai web app](https://otter.ai) | Web UI | Official interface, no CLI or API access |
| [otterai-api](https://github.com/gmchad/otterai-api) | Python library | API wrapper only, no CLI — this project builds on it |
| Manual export | Web UI | One-at-a-time downloads from the Otter.ai dashboard |

## Development

```bash
uv sync --dev        # install dependencies
uv run pytest        # run tests
```

## Acknowledgements

Based on [gmchad/otterai-api](https://github.com/gmchad/otterai-api) by Chad Lohrli, with CLI functionality from [PR #9](https://github.com/gmchad/otterai-api/pull/9) by [@andrewfurman](https://github.com/andrewfurman).

## License

MIT
