- Python 100%
Document JavaScript tooling preference to use bun and bunx instead of npm and npx in agent workflow notes. Keep this guidance alongside other remembered execution conventions. Co-Authored-By: opencode noreply@opencode.ai |
||
|---|---|---|
| src/frcmon | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
frcmon
frcmon monitors FRC event schedules and livestream signals for one or more teams, then sends updates through a pluggable messaging sink.
Current messaging provider:
- Telegram Bot API
Built-in runtime capabilities:
- scrape event result schedules (
practice,qualifications,playoffs) - detect schedule additions, removals, and reschedules
- send 5-minute and match-start notifications for monitored teams
- monitor a YouTube livestream with configurable vision, transcription, and summary models
Installation (uv)
uv sync
Optional local media analysis (OCR + speech transcription):
uv sync --extra media
System dependencies:
ffmpeg(for stream capture)tesseract(for OCR)- no browser install is required for schedule scraping (uses direct HTML requests)
Quick start
uv run frcmon init --event-url https://frc-events.firstinspires.org/2026/MNDU --team 3883
uv run frcmon notifications telegram --token <BOT_TOKEN> --chat-id <CHAT_ID>
uv run frcmon notifications provider telegram
uv run frcmon serve
If you have a bot token but no chat ID yet:
uv run frcmon notifications telegram --token <BOT_TOKEN>
# send /start or any message to your bot first
uv run frcmon notifications telegram discover-chat
CLI
frcmon serve # run monitor loop
frcmon schedule refresh # one-off scrape + state update
frcmon media test-video <URL> # test media pipeline on arbitrary video
frcmon team add 3883 # add monitored team
frcmon team remove 3883 # remove monitored team
frcmon team list # list monitored teams
frcmon config show # inspect current config
frcmon config set-event <URL> # set event page
frcmon config model ... # configure summary/vision/transcription models
frcmon notifications config # configure pre-match/start notification behavior
frcmon notifications test # send test message via configured provider
frcmon notifications provider ... # choose provider (console/telegram)
frcmon notifications telegram ... # set telegram credentials
frcmon notifications telegram discover-chat # auto-discover chat_id from getUpdates
Use --all-teams as a global option to monitor every team for a command run:
uv run frcmon --all-teams serve
uv run frcmon --all-teams schedule refresh --notify
Adjust notification toggles/timing:
uv run frcmon notifications config --pre-match --match-start --pre-match-minutes 5
uv run frcmon notifications test
Configure test-match behavior and idle stream monitoring:
uv run frcmon notifications config --monitor-idle-stream --ignore-test-summaries --no-transcribe-test-matches --notify-test-match-team
Test the media pipeline on recorded video (useful when no live matches are active):
uv run frcmon media test-video "https://www.youtube.com/watch?v=NlrtRQ2btkQ" --duration-seconds 90 --max-segments 6
uv run frcmon media test-video "https://www.youtube.com/watch?v=NlrtRQ2btkQ" --offset-seconds 300 --duration-seconds 60
# end-to-end replay through live notification pipeline
uv run frcmon media test-video "https://www.youtube.com/watch?v=NlrtRQ2btkQ" --e2e
# send replay notifications to configured provider (Telegram/console)
uv run frcmon media test-video "https://www.youtube.com/watch?v=NlrtRQ2btkQ" --e2e --send
media test-video uses the configured vision screenshot interval (monitor.frame_interval_seconds).
The default is defined by DEFAULT_VISION_FRAME_INTERVAL_SECONDS in src/frcmon/config.py.
When --max-segments truncates analysis, frcmon still includes the final video frame segment.
frcmon serve emits info-level runtime logs, including newly scraped schedule entries and the next scheduled entry when a monitored match starts or ends.
When test matches are detected from livestream vision, frcmon can suppress summaries, disable transcription, and notify you if monitored teams appear in the detected test-match lineup.
Model backends
frcmon uses three media-model roles:
- summary model (LLM for user-facing live summaries)
- vision model (analyzes screenshots for scoreboard/context)
- transcription model (speech-to-text for commentary)
Each role is swappable via frcmon config model with either local or OpenAI-compatible providers (cloud or self-hosted).
At runtime, frcmon loads ./.env automatically (without overriding already-exported variables), logs model backend key-env status on startup, and logs a one-time authentication success line after the first successful OpenAI-compatible request.
Examples:
# local defaults
uv run frcmon config model --target summary --provider local
uv run frcmon config model --target vision --provider local
uv run frcmon config model --target transcription --provider local --model base
# OpenAI-compatible endpoint (cloud or self-hosted)
uv run frcmon config model --target summary --provider openai-compatible --model gpt-4o-mini --base-url https://api.openai.com/v1 --api-key-env OPENAI_API_KEY
uv run frcmon config model --target vision --provider openai-compatible --model gpt-4o-mini --base-url https://api.openai.com/v1 --api-key-env OPENAI_API_KEY
uv run frcmon config model --target transcription --provider openai-compatible --model gpt-4o-mini-transcribe --base-url https://api.openai.com/v1 --api-key-env OPENAI_API_KEY
For OpenAI-compatible transcription, use a transcription-capable model (gpt-4o-mini-transcribe, gpt-4o-transcribe, or whisper-1). If a chat model is configured by mistake, frcmon warns and retries with gpt-4o-mini-transcribe.
Notes on livestream handling
frcmonresolves a direct stream URL withyt-dlp- it keeps a continuous
ffmpegprocess per selected webcast URL - periodic frame captures are OCR-processed for score changes
- audio segments are transcribed (when whisper is installed)
- notable commentary and lead changes are posted as messages
Development
uv sync --extra dev
uv run pytest
Test suite notes:
- scraper tests use stored HTML fixtures in
tests/fixtures/ - network access is blocked during tests to keep runs deterministic and offline-safe