BRISTLENOSE(1)

NAME
bristlenose - user-research transcription and quote extraction engine

SYNOPSIS
bristlenose [command] [options]
bristlenose run input-dir [-o output-dir] [-p project-name] [options]
bristlenose transcribe input-dir [-o output-dir] [options]
bristlenose analyze transcripts-dir [-o output-dir] [options]
bristlenose render [output-dir] [options]
bristlenose doctor
bristlenose configure provider [-k key]
bristlenose help [topic]

DESCRIPTION
bristlenose processes user-research interview recordings into structured, themed, timestamped quotes. It transcribes audio locally using Whisper, extracts and enriches quotes via LLM (Claude, ChatGPT, Azure OpenAI, Gemini, or local models via Ollama), groups them by screen and theme, and renders a browsable HTML report. Nothing is uploaded; recordings stay on your machine.

The HTML report includes sections (grouped by screen), themes (cross-participant patterns), a sentiment histogram, friction points, user journeys, clickable timecodes with a popout video player, favourite quotes with CSV export, inline editing, and a tag system with auto-suggest.

COMMANDS

run Full pipeline: ingest files, transcribe, identify speakers, extract quotes, cluster by screen, group by theme, update participant registry, render HTML and Markdown reports. Requires an API key. PII redaction is off by default; use --redact-pii to enable.

transcribe
    Transcription only. No LLM calls, no API key needed. Produces raw transcript files in bristlenose-output/transcripts-raw/.

analyze
    Run LLM analysis on existing transcript .txt files. Skips ingestion and transcription. Useful after reviewing or editing raw transcripts.

analyse
    British English alias for analyze.

render
    Re-render reports from existing intermediate JSON data. No transcription, no LLM calls, no API key needed. Useful after CSS or JavaScript changes.

doctor
    Check runtime dependencies and show tailored fix instructions. Tests FFmpeg, transcription backend, Whisper model cache, API key validity, network connectivity, PII redaction dependencies, and disk space. Also runs automatically on first invocation and as a pre-flight check before pipeline commands.

configure provider [-k KEY]
    Store API credentials securely in the system credential store. Provider can be claude (or anthropic), chatgpt (or openai, gpt), azure (or azure-openai), or gemini (or google). The key is validated with a test API call before storing (Azure validates via bristlenose doctor instead, since it also needs endpoint and deployment). Use -k to provide the key non-interactively.

help [topic]
    Show detailed help. Topics: commands, config, workflows, or any command name.

OPTIONS

  Global options

-V, --version
    Show version and exit.

--help
    Show command help and exit.

  Options for run

-o, --output DIR
    Output directory. Default: bristlenose-output/ inside the input folder.

-p, --project NAME
    Project name for the report header. Defaults to the input folder name.

-b, --whisper-backend BACKEND
    Transcription backend: auto (detect hardware), mlx (Apple Silicon GPU), faster-whisper (CUDA/CPU). Default: auto.

-w, --whisper-model MODEL
    Whisper model size: tiny, base, small, medium, large-v3, large-v3-turbo. Default: large-v3-turbo.

-l, --llm PROVIDER
    LLM provider: anthropic (or claude), openai (or chatgpt), azure (or azure-openai), google (or gemini), local (or ollama). Default: anthropic. The google provider uses Google Gemini (budget option). The local provider uses Ollama for free, private, offline analysis. The azure provider uses Azure OpenAI Service for enterprise environments.

--redact-pii
    Redact personally identifying information from transcripts. PII is retained by default.

--retain-pii
    Retain PII in transcripts (default behaviour). Mutually exclusive with --redact-pii.

--skip-transcription
    Skip audio transcription (use existing transcripts).

-c, --config PATH
    Path to a bristlenose.toml config file.

--clean
    Delete the output directory before running.

-v, --verbose
    Enable verbose logging.

  Options for transcribe

-o, --output DIR
    Output directory.

-w, --whisper-model MODEL
    Whisper model size.

-v, --verbose
    Enable verbose logging.

  Options for analyze

-o, --output DIR
    Output directory.

-p, --project NAME
    Project name.

-l, --llm PROVIDER
    LLM provider.

-v, --verbose
    Enable verbose logging.

  Options for render

-i, --input DIR
    Original input directory for video linking. Auto-detected if not specified.

-p, --project NAME
    Project name.

--clean
    Accepted for consistency but ignored — render is always non-destructive (overwrites reports only, never touches transcripts, people.yaml, or intermediate data).

-v, --verbose
    Enable verbose logging.

  Options for configure

-k, --key KEY
    API key to store. If not provided, prompts interactively.

CONFIGURATION
Settings are loaded in order (last wins):

1.  Built-in defaults

2.  .env file (searched upward from the current directory)

3.  Environment variables with prefix BRISTLENOSE_

4.  CLI flags

API keys have special priority: system credential store → environment variable → .env file. Use bristlenose configure claude, bristlenose configure chatgpt, bristlenose configure azure, or bristlenose configure gemini to store keys securely in the system credential store (macOS Keychain, Linux Secret Service).

  API keys

BRISTLENOSE_ANTHROPIC_API_KEY
    Anthropic API key.

BRISTLENOSE_OPENAI_API_KEY
    OpenAI API key.

BRISTLENOSE_GOOGLE_API_KEY
    Google Gemini API key.

  Azure OpenAI settings

BRISTLENOSE_AZURE_API_KEY
    Azure OpenAI API key (from the Azure portal).

BRISTLENOSE_AZURE_ENDPOINT
    Azure OpenAI endpoint URL (e.g. https://my-resource.openai.azure.com/).

BRISTLENOSE_AZURE_DEPLOYMENT
    Azure OpenAI deployment name (defined in the Azure portal, not a model name).

BRISTLENOSE_AZURE_API_VERSION
    Azure OpenAI API version. Default: 2024-10-21.

  LLM settings

BRISTLENOSE_LLM_PROVIDER
    anthropic, openai, azure, google, or local. Default: anthropic.

BRISTLENOSE_LLM_MODEL
    Model name. Default: claude-sonnet-4-20250514.

BRISTLENOSE_LLM_MAX_TOKENS
    Maximum response tokens. Default: 8192.

BRISTLENOSE_LLM_TEMPERATURE
    Sampling temperature. Default: 0.1.

BRISTLENOSE_LLM_CONCURRENCY
    Parallel LLM calls. Default: 3.

  Local LLM settings (Ollama)
When no API key is configured and you run bristlenose, it offers an interactive choice: Local AI (free via Ollama), Claude, or ChatGPT. If you choose Local and Ollama isn't installed, bristlenose offers to install it automatically (Homebrew on macOS, snap on Linux, curl script fallback). If Ollama is installed but not running, bristlenose will start it for you.

BRISTLENOSE_LOCAL_URL
    Ollama API endpoint. Default: http://localhost:11434/v1.

BRISTLENOSE_LOCAL_MODEL
    Local model name. Default: llama3.2:3b. Other options: llama3.1:8b, mistral:7b, qwen2.5:7b.

  Transcription settings

BRISTLENOSE_WHISPER_BACKEND
    auto, mlx, or faster-whisper. Default: auto.

BRISTLENOSE_WHISPER_MODEL
    Model size. Default: large-v3-turbo.

BRISTLENOSE_WHISPER_LANGUAGE
    Language code. Default: en.

BRISTLENOSE_WHISPER_DEVICE
    Device for faster-whisper: cpu, cuda, or auto. Default: auto.

BRISTLENOSE_WHISPER_COMPUTE_TYPE
    Compute type for faster-whisper: int8, float16, or float32. Default: int8.

  PII settings

BRISTLENOSE_PII_ENABLED
    Enable PII redaction. Default: false.

BRISTLENOSE_PII_LLM_PASS
    Extra LLM-based PII pass. Default: false.

BRISTLENOSE_PII_CUSTOM_NAMES
    Comma-separated list of additional names to redact.

  Pipeline settings

BRISTLENOSE_MIN_QUOTE_WORDS
    Minimum words per extracted quote. Default: 5.

BRISTLENOSE_MERGE_SPEAKER_GAP_SECONDS
    Gap threshold for merging consecutive speaker segments. Default: 2.0.

INPUT FILES
bristlenose accepts any mix of audio, video, subtitle, and transcript files:

    Audio:       .wav .mp3 .m4a .flac .ogg .wma .aac
    Video:       .mp4 .mov .avi .mkv .webm
    Subtitles:   .srt .vtt
    Transcripts: .docx (Microsoft Teams exports), .txt

Files sharing a name stem (e.g. p1.mp4 and p1.srt) are treated as a single session. When subtitles or transcripts exist, transcription is skipped for that session.

Platform naming conventions are auto-detected for session grouping: Microsoft Teams recording/transcript suffixes, Zoom cloud prefixes and meeting IDs, Zoom local recording folders, and Google Meet parenthetical timestamps are all stripped before stem comparison.

OUTPUT
Output goes inside the input folder by default (avoids collisions when processing multiple projects):

    interviews/                          input folder
      bristlenose-output/                output folder (inside input)
        bristlenose-interviews-report.html    browsable report
        bristlenose-interviews-report.md      Markdown version
        people.yaml                           participant registry
        assets/
          bristlenose-theme.css               stylesheet
          bristlenose-logo.png                logo (light)
          bristlenose-logo-dark.png           logo (dark)
          bristlenose-player.html             popout video player
        sessions/
          transcript_s1.html                  per-session transcript pages
          transcript_s2.html
        transcripts-raw/                      one .txt and .md per session
        transcripts-cooked/                   PII-redacted (only with --redact-pii)
        .bristlenose/
          intermediate/                       JSON snapshots for re-rendering
          temp/                               FFmpeg scratch files

EXAMPLES
Full pipeline run (output created inside input folder):

    bristlenose run ./interviews/
    # Creates ./interviews/bristlenose-output/

Full pipeline with custom output location:

    bristlenose run ./interviews/ -o ./results/ -p "Q1 Usability Study"

Transcribe only (no API key needed):

    bristlenose transcribe ./interviews/

Use Azure OpenAI (enterprise):

    export BRISTLENOSE_AZURE_ENDPOINT=https://my-resource.openai.azure.com/
    export BRISTLENOSE_AZURE_DEPLOYMENT=gpt-4o-research
    bristlenose configure azure
    bristlenose run ./interviews/ --llm azure

Use Gemini (budget option):

    bristlenose configure gemini
    bristlenose run ./interviews/ --llm gemini

Use local AI via Ollama (free, no API key):

    bristlenose run ./interviews/ --llm local
    # Requires Ollama running: ollama serve

Analyse existing transcripts:

    bristlenose analyze ./interviews/bristlenose-output/transcripts-raw/

Re-render after CSS changes (no API key needed):

    cd ./interviews/ && bristlenose render
    # Or specify explicitly:
    bristlenose render ./interviews/bristlenose-output/

Check dependencies and setup:

    bristlenose doctor

Show configuration reference:

    bristlenose help config

HARDWARE
Transcription hardware is auto-detected:

•   Apple Silicon: MLX on Metal GPU

•   NVIDIA: faster-whisper with CUDA

•   Other: CPU fallback

FILES

.env
    Environment variables file, searched upward from the current directory.

.env.example
    Template with all available configuration variables.

bristlenose.toml
    Optional TOML configuration file.

EXIT STATUS

0   Success.

1   Error (missing input, configuration problem, pipeline failure).

BUGS
Report bugs at https://github.com/cassiocassio/bristlenose/issues.

AUTHOR
Cassio https://github.com/cassiocassio

LICENSE
AGPL-3.0. See the LICENSE file in the source distribution.

SEE ALSO
ffmpeg(1), whisper(1)

Full documentation: https://github.com/cassiocassio/bristlenose