Modern TypeScript transcription system with BullMQ, Redis, and Whisper.cpp integration
โจ Automated Deployment: Push to
mainand changes deploy automatically to production!
Palantir - The seeing stones of Middle-earth that enable communication across vast distances. Like the ancient palantรญri, this system "sees" audio content and communicates its transcribed essence across your infrastructure.
Transcription Palantir is a BACKEND SERVICE - it focuses exclusively on audio transcription processing. It is NOT intended for direct frontend access.
- โ
Frontends โ Access via Mithrandir Unified API (port 8080) at
/transcription/* - โ Backend Services โ Can access directly at port 9003 for service-to-service communication
- โ DO NOT configure frontends to access port 9003 directly
The Unified API acts as an API Gateway/BFF (Backend for Frontend), providing:
- Consistent API contracts across all services
- Centralized CORS, authentication, and rate limiting
- Service abstraction and flexibility
- Data aggregation from multiple backend services
- Modern Queue System: BullMQ + Redis for robust job management
- High Performance: Whisper.cpp integration for fast transcription
- Scalable Architecture: Auto-scaling workers with PM2/Docker
- Real-time Monitoring: WebSocket dashboard with live updates
- Type Safety: Full TypeScript coverage with strict checking
- Production Ready: Health checks, metrics, and comprehensive logging
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ File Watcher โโโโโถโ BullMQ Queue โโโโโถโ Worker Cluster โ
โ (Chokidar) โ โ (Redis) โ โ (PM2/Docker) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Fastify API โ โ Single Source โ โ Whisper.cpp โ
โ (Dashboard) โ โ of Truth โ โ (Transcriber) โ
โโโโโโโโโโโโโโโโโโโ โ (Redis Only) โ โโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโ
๐๏ธ SQLite Retired: As of 2025-11-21, SQLite database was permanently retired. BullMQ (Redis) is now the single source of truth for all job data, eliminating sync issues and simplifying the architecture. See SQLITE_RETIREMENT_NOTICE.md for details.
- Runtime: Bun (primary) / Node.js (fallback)
- Language: TypeScript with strict type checking
- Queue: BullMQ + Redis (single source of truth, SQLite retired)
- API: Fastify with Swagger documentation
- Transcription: Whisper.cpp (faster than Python alternatives)
- Process Management: PM2 / Docker Swarm
- Monitoring: Prometheus metrics + custom dashboard
- Bun >= 1.0.0 (or Node.js >= 18.0.0)
- Redis >= 6.0.0
- Whisper.cpp (compiled binary)
# Clone and setup
git clone <repository-url>
cd transcription-palantir
bun install
# Configure environment
cp .env.example .env
# Edit .env with your settings
# Start Redis (if not running)
redis-server
# Development mode
bun run dev
# Production build
bun run build
bun run start# Core Settings
NODE_ENV=development
PORT=3000
LOG_LEVEL=info
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# Whisper Configuration
WHISPER_MODEL=small
WHISPER_BINARY_PATH=/usr/local/bin/whisper
COMPUTE_TYPE=int8
# File Processing
WATCH_DIRECTORY=/path/to/audio/files
OUTPUT_DIRECTORY=/path/to/transcripts
MAX_WORKERS=4# Start all services
bun run docker:run
# Or start individually
bun run start:api # API server
bun run start:worker # Transcription workers
bun run start:watcher # File watcherGET /api/v1/health- Health checkGET /api/v1/metrics- Prometheus metricsGET /api/v1/jobs- List transcription jobsPOST /api/v1/jobs- Create new transcription jobGET /api/v1/jobs/:id- Get job statusDELETE /api/v1/jobs/:id- Cancel jobGET /api/v1/monitor/queue- Queue monitoringGET /api/v1/monitor/workers- Worker statusGET /api/v1/monitor/status- System status
โ Frontends should use these endpoints:
GET http://mithrandir:8080/transcription/jobs- List jobs (proxied to Palantir)POST http://mithrandir:8080/transcription/jobs- Create job (proxied to Palantir)GET http://mithrandir:8080/transcription/jobs/:id- Get job (proxied to Palantir)GET http://mithrandir:8080/api/dashboard/stats- Dashboard statisticsGET http://mithrandir:8080/api/dashboard/activity- Recent activity
See Mithrandir Unified API documentation for complete API reference.
npm test # Run all tests (using Vitest)
npm run test:watch # Watch mode
npm run test:coverage # With coveragebun run lint # ESLint
bun run lint:fix # Auto-fix issues
bun run format # Prettier formattingPalantir runs as a user-level systemd service on Mithrandir. The service file is at scripts/transcription-palantir.service.
Install the service:
# Copy service file to systemd user directory
cp scripts/transcription-palantir.service ~/.config/systemd/user/transcription-palantir.service
# Reload, enable, and start
systemctl --user daemon-reload
systemctl --user enable transcription-palantir
systemctl --user start transcription-palantir
# Check status
systemctl --user status transcription-palantirDeploy code updates:
# On Mithrandir
cd ~/transcription-palantir
git pull
bun install
bun run build
systemctl --user restart transcription-palantirThe systemd unit includes three layers of defense against orphaned bun child processes:
KillMode=control-group- Kills the entire cgroup (main process + all children) on stop. This is the primary defense.TimeoutStopSec=15- If graceful shutdown hangs, systemd sends SIGKILL after 15 seconds.ExecStopPost=fuser -k 9003/tcp- Force-kills anything still bound to port 9003 after stop.
Incident (2026-02-01 to 2026-02-20): Palantir received SIGTERM but a bun child process survived and held port 9003 at 99.9% CPU for 19 days. The systemd service couldn't restart because of EADDRINUSE, producing 1,019 failed restart attempts in the log. The zombie was only cleared by manual
kill -9. The three systemd directives above were added to prevent recurrence.
# Build and run with Docker Compose
bun run docker:build
bun run docker:run
# Scale workers
docker-compose up --scale worker=4- Health Checks:
/healthendpoint with detailed system status - Metrics: Prometheus-compatible metrics at
/metrics - Logging: Structured JSON logs with configurable levels
- Dashboard: Real-time job monitoring with WebSocket updates
- Rate Limiting: Configurable API rate limits
- CORS: Proper cross-origin resource sharing
- Helmet: Security headers and protection
- Input Validation: Zod schema validation
The Transcription Palantir API uses semantic versioning with URL-based version prefixes (/api/v1/*). We maintain backward compatibility and provide clear migration paths for breaking changes.
Key Points:
- Current version: v1 (
/api/v1/*) - Breaking changes require new version prefix (e.g.,
/api/v2/*) - Non-breaking changes can be added to existing version
- OpenAPI spec available at
/documentation/json - Interactive API docs at
/docs
See API Versioning Policy for complete details on:
- Breaking vs non-breaking changes
- Version support policy
- Migration guidelines
Consumer applications can automatically generate TypeScript types from the OpenAPI specification for type-safe API integration.
Quick Start:
# Install openapi-typescript
npm install --save-dev openapi-typescript
# Add to package.json
{
"scripts": {
"generate:types": "openapi-typescript http://palantir.tailnet:3001/documentation/json -o src/types/palantir.d.ts"
}
}
# Generate types
npm run generate:typesBenefits:
- โ Type-safe API client code
- โ Compile-time contract enforcement
- โ Automatic detection of breaking changes
- โ IDE autocomplete and IntelliSense
See Consumer Type Generation Guide for:
- Complete setup instructions
- Usage examples
- Best practices
- Troubleshooting
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
MIT License - see LICENSE file for details.
Built with โค๏ธ for the Mithrandir ecosystem