- Python 99.4%
- Nix 0.4%
- Shell 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| tests | ||
| .envrc | ||
| .gitignore | ||
| config.json.example | ||
| extract_diffs.py | ||
| flake.lock | ||
| flake.nix | ||
| forgejo-daily-report.py | ||
| forgejo_daily_report.py | ||
| post_note.py | ||
| pyrightconfig.json | ||
| README.md | ||
| requirements.txt | ||
| setup.sh | ||
forgejo-daily-report
Generates a daily summary of Forgejo repository activity and posts it to both TriliumNext and BookStack.
For each repo with commit or issue activity on the target day, it:
- Fetches commits via the Forgejo API
- Fetches issues and milestones opened, updated, or closed that day
- Fetches the diff for each commit
- Syncs the matching Engram project and extracts memories created that UTC day
- Sends the diffs, commit messages, issue and milestone context, and memories to Ollama for an HTML summary
- Posts the summary, commits, compact issue/milestone activity lists, and verbatim memories as a child note under that day's Trilium date note and as a page in the BookStack Project Logs shelf
- Generates a separate conversational voice summary from the same source material, renders it as a Fern Brady-voiced MP3, and posts it to the
forgejo-reportsntfy topic
Engram is optional. A missing binary, failed cloud sync, or invalid export produces a warning and the normal Forgejo-only report continues.
Requirements
- Python 3.11+
- An Ollama instance with a model loaded
- A TriliumNext instance with ETAPI enabled
- A BookStack instance reachable by the scheduled job
- A Forgejo instance with an API token
- Optional: an Engram v1.17-compatible binary and access to an Engram cloud server
- Optional: Pocket TTS and a Hugging Face token for repository audio notifications
Setup
cp config.json.example config.json
# Edit config.json with your details
direnv allow
The included .envrc loads a Nix development shell with Python, requests, and Pyright. Once allowed, run the scripts directly; no virtual environment is needed.
Usage
# Report yesterday's UTC activity.
python forgejo_daily_report.py
# Report one specific UTC day.
python forgejo_daily_report.py 2026-07-13
# Backfill from the given UTC day through yesterday.
python forgejo_daily_report.py --backfill 2026-07-01
# Rebuild existing successful reports with current Forgejo context.
python forgejo_daily_report.py 2026-07-13 --refresh
# Single-date run with text and voice reports explicitly enabled.
python forgejo_daily_report.py 2026-07-13 --voice --text
# Backfill text reports only (the backfill default).
python forgejo_daily_report.py --backfill 2026-07-01
# Backfill with voice reports enabled, but no text reports.
python forgejo_daily_report.py --backfill 2026-07-01 --voice --no-text
--backfill fetches the repository list and each repository's Forgejo activity once for the full date range, buckets it by UTC day, then applies the normal report flow to each day. It continues if an individual day fails and exits non-zero after the range if any dates failed. Voice reports default to on for a single-date run and off for backfills; use --voice or --no-voice to override that default. Text reports default to on for all runs; use --no-text to intentionally disable Trilium and BookStack report generation/delivery, or --text to state the default explicitly. Add --test to generate summaries without publishing. --refresh checks existing successful text reports against current Forgejo activity, validation results, API states, and the selected model. It only replaces both text reports when those inputs or the model changed; voice-only runs are not suppressed by existing text reports.
Configuration
All settings can be provided via config.json (takes precedence) or environment variables.
| Key | Description | Default |
|---|---|---|
FORGEJO_URL |
Base URL of your Forgejo instance | https://git.nimmog.uk |
FORGEJO_TOKEN |
API token with read:repository, read:issue, and read:user scopes |
(required) |
FORGEJO_USER |
Forgejo username whose repos to report on | nimmo |
OLLAMA_URL |
Ollama API base URL | http://nova.mesh:11434 |
OLLAMA_MODEL |
Model to use for summarisation | qwen3.6:35b-a3b-q8_0 |
OLLAMA_NUM_CTX |
Ollama context-window allocation | 262144 |
OLLAMA_TIMEOUT |
Ollama request timeout in seconds | 3600 |
CODEX_MODEL |
Model to use for the Codex fallback | gpt-5.5 |
TRILIUM_URL |
TriliumNext base URL | https://notes.nimmog.uk |
TRILIUM_TOKEN |
ETAPI token | (required) |
TRILIUM_REPOSITORIES_NOTE_ID |
Parent note for repository report indexes | QUadK9c6ibZA |
HF_TOKEN |
Hugging Face token used to download Pocket TTS weights | (optional; required for first model download) |
POCKET_TTS_BIN |
Pocket TTS executable | pocket-tts |
POCKET_TTS_VOICE |
Voice sample WAV | ../daily-briefing/voice_samples/fern_brady.wav |
POCKET_TTS_FALLBACK_VOICE |
Built-in voice if sample cloning fails | anna |
POCKET_TTS_TIMEOUT |
TTS timeout in seconds | 600 |
FFMPEG_BIN |
ffmpeg executable used to convert Pocket TTS WAV output to MP3 | ffmpeg |
MP3_BITRATE |
MP3 encoding bitrate | 96k |
NTFY_BASE_URL |
ntfy server base URL | (optional; disables audio when absent) |
NTFY_API_KEY |
ntfy bearer token | (optional; disables audio when absent) |
NTFY_TOPIC |
ntfy topic for repository audio | forgejo-reports |
BOOKSTACK_URL |
BookStack base URL | https://wiki.nimmog.uk |
BOOKSTACK_ID |
BookStack API token ID | (required) |
BOOKSTACK_SECRET |
BookStack API token secret | (required) |
ENGRAM_ENABLED |
Enable same-day Engram memory collection | true |
ENGRAM_BINARY |
Engram executable; falls back to ./engram, then PATH |
(auto-detect) |
ENGRAM_CLOUD_SERVER |
Engram cloud endpoint used for project sync | http://10.10.0.2:18080 |
ENGRAM_CLOUD_TOKEN |
Bearer token for Engram cloud | (optional for unauthenticated servers) |
ENGRAM_DATA_DIR |
Persistent local Engram database directory | Engram default (~/.engram) |
MAX_DIFF_BYTES |
Max bytes of diff to send per repo | 100000 |
DIFF_EXCLUDE_PATTERNS |
Extra filename patterns to exclude from diffs (config.json only, as a list) | [] |
Engram on media1
Place the engram binary beside forgejo-daily-report.py, make it executable, and configure the Vega cloud endpoint and token in the private config.json. Keep ENGRAM_DATA_DIR on persistent storage writable by the cron user.
chmod +x ./engram
./engram version
For each repository with commits, the report runs a project-scoped cloud sync using the repository name. If the local project has not been enrolled, it enrolls it and retries once. Engram failures never mark or block the Forgejo report.
Usage
# Report on yesterday (default)
venv/bin/python3 forgejo-daily-report.py
# Report on a specific date
venv/bin/python3 forgejo-daily-report.py 2026-03-05
Cron
0 1 * * * /home/nimmo/scripts/forgejo-daily-report/venv/bin/python3 /home/nimmo/scripts/forgejo-daily-report/forgejo-daily-report.py
Trilium notes
Each generated note is tagged with:
git-report— allows searching across all reportsiconClass=bx bxl-git— git icon in the note tree<repo-name>=<date>— e.g.nixos-config=2026-03-05, for per-repo history searches
When matching Engram memories exist, the note also contains a chronological Memories section with escaped verbatim content. Those memories are supplied to the summary model as additional context. Issue activity and Milestone activity sections list each item opened, updated, or closed that UTC day. Updated issues include bounded same-day comment and timeline context when available. To keep reports readable, descriptions are not copied into the note; the first 1,500 characters of newly opened issues and milestones are supplied only to the summary model as context.
Reports also show Forgejo Actions and commit-status signals for the reported commits. These are validation signals, not proof that a deployment completed. Report metadata records the status of issue, milestone, Actions, and commit-status API sources; repositories with issue tracking disabled are skipped quietly.
When TRILIUM_REPOSITORIES_NOTE_ID is configured, the script also creates a repository note beneath that parent and adds every report as an additional Trilium parent. Reports therefore remain under their daily date note while also appearing in their repository's report history.
BookStack pages
Reports are stored on a Project Logs shelf. Each repository has one book on that shelf, each repository book has YYYY-MM chapters, and each daily report is a dated page within its month chapter. Shelves, books, and chapters are created automatically when first needed.
Repository books are refreshed from Forgejo metadata: their description records the repository URL and default branch, while tags record repository name, Forgejo URL, visibility, default branch, reported languages, and any available license, topics, or archived status.
Each report page is tagged with git-report=true, repository=<repo>, report-date=<YYYY-MM-DD>, model=<summary model>, and a forgejo-report-inputs fingerprint. The fingerprint includes activity and validation outcomes (including successes and failures), so refresh can avoid an unchanged regeneration. A report that could not be summarised also receives forgejo-failed=true.
Trilium and BookStack are independent delivery targets: a lookup or posting failure in one is logged but does not prevent delivery to the other. Create a BookStack API token with access to the Project Logs shelf and ensure the configured API URL is reachable from the cron host.