README.md

Skraak

Acoustic monitoring database toolkit in Go. Use as an MCP server for AI assistants or as a CLI for direct access.

Installation

go build -o skraak

Usage

MCP Server

Start the server for use with Claude Desktop or other MCP clients:

./skraak mcp --db ./db/skraak.duckdb

Claude Code config* claude mcp add --transport stdio skraak_mcp -- /home/david/go/src/skraak/skraak mcp --db /home/david/go/src/skraak/db/skraak.duckdb

claude mcp add --transport stdio test_mcp -- /home/david/go/src/skraak/skraak mcp --db /home/david/go/src/skraak/db/test.duckdb

remove: claude mcp remove skraak_mcp

Claude Desktop config (~/.config/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "skraak": {
      "command": "/home/david/go/src/skraak/skraak",
      "args": ["mcp", "--db", "/home/david/go/src/skraak/db/skraak.duckdb"]
    }
  }
}

CLI Commands

# Execute SQL query
./skraak sql --db ./db/skraak.duckdb "SELECT COUNT(*) FROM file WHERE active = true"

# Create resources
./skraak create dataset --db ./db/skraak.duckdb --name "My Dataset" --type unstructured
./skraak create location --db ./db/skraak.duckdb --dataset abc123 --name "Site A" --lat -36.85 --lon 174.76 --timezone Pacific/Auckland
./skraak create cluster --db ./db/skraak.duckdb --dataset abc123 --location loc456 --name "2024-01" --sample-rate 250000
./skraak create pattern --db ./db/skraak.duckdb --record 60 --sleep 1740

# Update resources
./skraak update dataset --db ./db/skraak.duckdb --id abc123 --name "Updated Name"
./skraak update location --db ./db/skraak.duckdb --id loc123 --name "Updated Name" --lat -36.85 --lon 174.76
./skraak update cluster --db ./db/skraak.duckdb --id cluster123 --name "Updated Name"
./skraak update pattern --db ./db/skraak.duckdb --id pattern123 --record 30 --sleep 1770

# Import commands
./skraak import file --db ./db/skraak.duckdb --dataset abc123 --location loc456 --cluster clust789 --path /path/to/file.wav
./skraak import folder --db ./db/skraak.duckdb --dataset abc123 --location loc456 --cluster clust789 --path /path/to/folder
./skraak import bulk --db ./db/skraak.duckdb --dataset abc123 --csv import.csv --log progress.log
./skraak import unstructured --db ./db/skraak.duckdb --dataset 4Sh8_7p1ocks --path "/media/david/Misc-2/Manu o Kahurangi kiwi survey (3)/Andrew Digby LSK - sorted files"
./skraak import selections --db ./db/skraak.duckdb --dataset abc123 --cluster clust789 --path /path/to/Clips_filter_date

# Export dataset (for collaboration, testing, or archival)
./skraak export dataset --db ./db/skraak.duckdb --id abc123 --output export.duckdb
./skraak export dataset --db ./db/skraak.duckdb --id abc123 --output export.duckdb --dry-run

# Event log replay (sync backup databases)
./skraak replay events --db ./backup.duckdb --log ./skraak.duckdb.events.jsonl
./skraak replay events --db ./backup.duckdb --log ./events.jsonl --dry-run
./skraak replay events --db ./backup.duckdb --log ./events.jsonl --last 10

# Call analysis (extract from ML predictions, review/classify)
./skraak calls from-preds --csv predictions.csv                    # Extract calls, write .data files
./skraak calls from-preds --csv preds.csv --dot-data=false > calls.json  # JSON output only
./skraak calls show-images --file recording.wav.data               # Display spectrograms
./skraak calls classify --folder ./data --reviewer David --bind k=Kiwi  # Interactive classification

skraak calls classify --folder 2025-02-25 --reviewer David --color --img-dims 600 --bind a=eurbla, --bind b=nezbel1, --bind c=comcha, --bind d=saddle3, --bind e=pipipi1, --bind f=nezfan1, --bind g=gryger1, --bind i=tui1, --bind k=kea1, --bind l=lotkoe1, --bind m=morepo2, --bind n=nezrob3, --bind o=soioys1, --bind p=malpar2, --bind r=riflem1, --bind s=silver3, --bind t=tomtit1, --bind u=nezpig2, --bind w=nezkak1,  --bind x=Noise, --bind z="Don't Know", --bind 1=Kiwi+Duet, --bind 2=Kiwi+Female, --bind 3=Kiwi+Male, --bind 4=Kiwi, --bind 5=Gecko

# File utilities
./skraak xxhash --file recording.wav     # XXH64 hash (same format as DB)
./skraak metadata --file recording.wav   # WAV metadata as JSON
./skraak time                            # Current time as JSON

Available Tools

MCP Tools (9 total)

Query:

  • execute_sql - Run SQL SELECT queries (JOINs, aggregates, CTEs supported)
  • get_current_time - Current time with timezone

Write:

  • create_or_update_dataset - Create or update a dataset
  • create_or_update_location - Create or update a location with GPS/timezone
  • create_or_update_cluster - Create or update a cluster within a location
  • create_or_update_pattern - Create or update a cyclic recording pattern

Import:

  • import_audio_files - Batch import WAV files from a folder
  • import_ml_selections - Import ML-detected selections from folder structure

CLI Commands

New Command Structure (2026-02-21): Verb-first commands for natural language flow

  • create dataset instead of dataset create
  • update location instead of location update

Query:

  • sql - Execute SQL queries directly
  • time - Get current time as JSON

Data Management:

  • create - Create new resources (dataset, location, cluster, pattern)
  • update - Update existing resources (dataset, location, cluster, pattern)

Import:

  • import bulk - Bulk import from CSV file (structured dataset)
  • import file - Import a single WAV file (structured dataset)
  • import folder - Import all WAV files from a folder (structured dataset)
  • import selections - Import ML selections from folder structure (structured dataset)

Export:

  • export dataset - Export a dataset with all related data to new database

Event Log:

  • replay events - Replay event log on backup database for synchronization

Call Analysis:

  • calls from-preds - Extract clustered calls from ML predictions CSV, write .data files
  • calls show-images - Display spectrogram images from .data file (Kitty/Sixel graphics)
  • calls classify - Interactive TUI for reviewing and classifying audio segments

Utilities:

  • xxhash - Compute XXH64 hash of a file (JSON output)
  • metadata - Extract WAV file metadata (JSON output)

Resources & Prompts

MCP server provides:

  • schema://full - Complete database schema
  • schema://table/{name} - Individual table definitions
  • 6 SQL workflow prompts teaching query patterns

Event Log

All mutating SQL operations (INSERT, UPDATE, DELETE) are automatically logged for backup synchronization.

Event log location: <database>.events.jsonl

Features:

  • SQL-level capture for complete fidelity
  • Only successful transactions logged (rollbacks discarded)
  • Includes tool name, SQL, parameters, timestamp

Replay on backup database:

# Replay all events
./skraak replay events --db ./backup.duckdb --log ./skraak.duckdb.events.jsonl

# Preview without executing
./skraak replay events --db ./backup.duckdb --log ./events.jsonl --dry-run

# Replay last N events
./skraak replay events --db ./backup.duckdb --log ./events.jsonl --last 10

Event format (JSONL):

{
  "id": "V1StGXR8_Z5jdHi6B-myT",
  "timestamp": "2026-02-18T14:30:22+13:00",
  "tool": "create_or_update_dataset",
  "queries": [{"sql": "INSERT INTO ...", "parameters": [...]}],
  "success": true,
  "duration_ms": 45
}

Dataset Export

Export a dataset with all related data to a new DuckDB database for collaboration, testing, or archival.

Use cases:

  • Collaboration: Export, send to collaborator, they return event log for replay
  • Testing: Create focused test database from production (100 MB vs 1.5 GB)
  • Archival: Snapshot a dataset at a point in time

Export:

# Export dataset to new database
./skraak export dataset --db ./db/skraak.duckdb --id abc123 --output export.duckdb

# Preview without creating file
./skraak export dataset --db ./db/skraak.duckdb --id abc123 --output export.duckdb --dry-run

# Overwrite existing export
./skraak export dataset --db ./db/skraak.duckdb --id abc123 --output export.duckdb --force

What's exported:

  • All rows owned by dataset (via dataset_id foreign key traversal)
  • Subset of reference data (species, patterns, filters used)
  • Creates empty event log file for changes

Re-import changes:

# After collaborator returns event log, replay on backup
./skraak replay events --db ./backup.duckdb --log export.duckdb.events.jsonl

Call Analysis

Extract and review bird calls from ML predictions using a three-step workflow.

Workflow:

  1. Extract calls from predictions:
# Write .data files alongside audio (default)
./skraak calls from-preds --csv predictions.csv

# JSON output only (no .data files)
./skraak calls from-preds --csv preds.csv --dot-data=false > calls.json

# Override filter name (parsed from CSV filename by default)
./skraak calls from-preds --csv preds.csv --filter my-filter
  1. Preview spectrograms:
# Display spectrograms from .data file (Kitty graphics protocol)
./skraak calls show-images --file recording.wav.data

# With L4 colormap (Black-Red-Yellow)
./skraak calls show-images --file recording.wav.data --color

# Use Sixel protocol (for non-Kitty terminals)
./skraak calls show-images --file recording.wav.data --sixel
  1. Interactive classification:
# Launch TUI for reviewing and classifying segments
./skraak calls classify --folder ./data --reviewer David --bind k=Kiwi

# Multiple key bindings
./skraak calls classify --folder ./data --reviewer David \
    --bind k=Kiwi --bind d='Kiwi+Duet' --bind n='Don''t Know'

# Single file mode
./skraak calls classify --file recording.wav.data --reviewer David --bind k=Kiwi

# With color and custom image size
./skraak calls classify --folder ./data --reviewer David --bind k=Kiwi --color --img-dims 224

Key bindings format:

  • k=Kiwi - Press 'k' to classify as Kiwi (species only)
  • d=Kiwi+Duet - Press 'd' to classify as Kiwi with Duet call type

Database

  • Production: ./db/skraak.duckdb
  • Testing: ./db/test.duckdb (use for development)

Development

# Run tests
go test ./...

# Run with coverage
go test -cover ./...

See CLAUDE.md for detailed development notes.