Documents the Homelab installation location and service name. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BLIGHT: CUE
A module in the BLIGHT ecosystem.
BLIGHT: CUE monitors Gitea repositories containing markdown files. When a push is received, it scans changed files for BLIGHT: trigger lines, sends the surrounding document to an AI model along with the instruction, and writes the result back to the file in-place — fully automated.
How It Works
- You write a
BLIGHT:trigger anywhere in a markdown file and push it to Gitea. - Gitea sends a webhook POST to this server.
- The server fetches the file, finds all
BLIGHT:triggers, and processes them one by one. - Each trigger is replaced with the AI's response at the exact position of the trigger line.
- The updated file is committed back to the repo automatically.
Trigger Syntax
BLIGHT: <your instruction here>
Examples:
This paragraph discusses は vs が in Japanese grammar.
BLIGHT: Explain the key differences between は and が based on the paragraph above.
## Next Section
BLIGHT: Spell check this entire document and list any errors found.
BLIGHT: Write a conclusion paragraph for this document.
Failure Behavior
If the AI call fails after 3 attempts, the trigger is replaced with:
<!-- BLIGHT_FAILED: your original instruction -->
You can re-trigger processing by editing the file to restore the original BLIGHT: line and pushing again.
Prerequisites
- Python 3.10+
- Access to your Gitea instance (via Tailscale or local network)
- A Google Gemini API key
- A Gitea personal access token with repository read/write permissions
Installation
# 1. Clone this repo onto the machine that will run the listener
git clone <this-repo-url>
cd BLIGHT--CUE
# 2. Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Copy the example env file and fill in your values
cp .env.example .env
Configuration
Edit .env with your values:
| Variable | Description |
|---|---|
GITEA_URL |
Base URL of your Gitea instance, no trailing slash |
GITEA_TOKEN |
Personal access token from Gitea → Settings → Applications |
GEMINI_API_KEY |
API key from Google AI Studio |
WEBHOOK_SECRET |
A secret string you choose — must match what you set in Gitea |
WEBHOOK_PORT |
Port the listener binds to (default: 5010) |
Running
python app.py
The server binds to 0.0.0.0:5010 (or your configured port). Keep it running as a service or in a screen/tmux session.
For production use, run it as a systemd service so it starts automatically on boot and restarts on failure.
1. Create the service file:
sudo nano /etc/systemd/system/blight-cue.service
Paste the following, adjusting the paths and user to match your setup:
[Unit]
Description=BLIGHT: CUE webhook listener
After=network.target
[Service]
User=artanis
WorkingDirectory=/home/artanis/Documents/BLIGHT_CUE
ExecStart=/home/artanis/Documents/BLIGHT_CUE/.venv/bin/python app.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
2. Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable blight-cue
sudo systemctl start blight-cue
3. Check it's running:
sudo systemctl status blight-cue
4. View logs:
journalctl -u blight-cue -f
Registering the Webhook in Gitea
If Gitea runs in Docker
Gitea containers cannot reach localhost on the host directly. The recommended approach is to use host.docker.internal, which Docker resolves to the host machine's IP.
1. Add extra_hosts to your Gitea docker-compose.yml:
services:
gitea:
image: gitea/gitea:latest
# ... your existing config ...
extra_hosts:
- "host.docker.internal:host-gateway"
2. Restart Gitea:
docker compose down && docker compose up -d
3. Find the host's IP from the container's perspective:
docker exec -it <gitea-container-name> ip route show default
This returns something like default via 172.20.0.1 dev eth0. That gateway IP is the host's address reachable from the container — use it as the webhook target.
Note:
host.docker.internalresolves to the defaultdocker0bridge (172.17.0.1) on Linux, which may not be reachable if Gitea is on a custom Docker network. Using the gateway IP directly is more reliable.
4. Whitelist the IP in Gitea's config:
environment:
- GITEA__webhook__ALLOWED_HOST_LIST=172.20.0.1 # replace with your gateway IP
5. Restart Gitea again after adding the environment variable.
Note: If CUE is not running when Gitea sends a webhook, the delivery will fail. You can use the Redeliver button in the webhook's delivery history to retry without needing to push again.
Registering the Webhook
Do this for each repository you want BLIGHT: CUE to watch.
- Open the repository in Gitea.
- Go to Settings → Webhooks → Add Webhook → Gitea.
- Set the fields:
- Target URL:
http://<gateway-ip>:5010/webhook(e.g.http://172.20.0.1:5010/webhook) - HTTP Method: POST
- Content Type:
application/json - Secret: the same value as
WEBHOOK_SECRETin your.env - Trigger On: Push events only
- Target URL:
- Click Add Webhook, then use Test Delivery to verify connectivity.
AI Provider
BLIGHT: CUE currently uses Google Gemini 2.5 Flash-Lite — the most cost-effective stable Gemini model (~$0.10/$0.40 per million tokens input/output).
Adding a New Provider
All AI providers implement the AIProvider abstract base class in ai/base.py:
from abc import ABC, abstractmethod
class AIProvider(ABC):
def complete(self, document: str, instruction: str) -> str:
...
To add a new provider (e.g. OpenRouter):
- Create
ai/openrouter.pyand implementAIProvider. - In
processor.py, replaceGeminiProvider()with your new class.
Project Structure
Blight_Reader/
├── app.py # Flask webhook server
├── processor.py # Trigger scanning and replacement logic
├── gitea_client.py # Gitea REST API wrapper
├── config.py # Environment config loader
├── ai/
│ ├── base.py # AIProvider abstract base class
│ └── gemini.py # Gemini 2.5 Flash-Lite implementation
├── requirements.txt
├── .env.example
└── README.md
Deployments
| Machine | Path | Service |
|---|---|---|
| Homelab | /home/artanis/Documents/BLIGHT_CUE |
blight-cue.service |
Part of the BLIGHT Ecosystem
BLIGHT: CUE is one module in a larger modular system called BLIGHT. Each module is independently deployable and communicates through Gitea repositories as the shared data layer.