Add CLAUDE.md with versioned changelog, update README

- Created CLAUDE.md with instructions to update changelog and README on
  every commit, version number (v1.2.0), and full changelog from v1.0.0
- Updated README: document-scope BLIGHT:: syntax, processing order,
  two-line failure format, complete_document() in AI provider section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 12:45:01 -05:00
parent 6d9dc5982b
commit a80f945701
2 changed files with 75 additions and 8 deletions

45
CLAUDE.md Normal file
View File

@@ -0,0 +1,45 @@
# CLAUDE.md — BLIGHT: CUE
## Instructions for Claude
- **Every commit**: Update the Changelog section below with a summary of what changed and bump the version number if appropriate.
- **Every commit**: If the changes affect anything documented in README.md (trigger syntax, failure behavior, setup, project structure, AI provider info, etc.), update README.md in the same commit.
---
## Version
**v1.2.0**
---
## Changelog
### v1.2.0
- Fixed loop re-processing: AI responses are sanitized by replacing `BLIGHT:` with `BLIGHT&#58;` before being written to the document, preventing the service's own commits from triggering another processing cycle.
- Branch awareness: branch is now extracted from `refs/heads/<branch>` in the push payload and passed to all Gitea read/write calls, so pushes to non-default branches are handled correctly.
- Commit messages now include the file path (e.g. `BLIGHT: process triggers in notes/todo.md`).
### v1.1.0
- Added `BLIGHT::` (double colon) document-scope trigger syntax. Unlike `BLIGHT:` which replaces only the trigger line, `BLIGHT::` replaces the entire file content with the AI's rewritten document.
- Multiple `BLIGHT::` triggers in one file are processed sequentially, each operating on the result of the previous.
- Inline `BLIGHT:` triggers are always processed before `BLIGHT::` triggers.
- Both trigger types are now case-insensitive (`blight:`, `BLIGHT:`, `Blight::`, etc. all match).
- Failure comments updated to two-line format:
```
<!-- BLIGHT_FAILED: <instruction> -->
<!-- BLIGHT_ERROR: <error message> -->
```
- Added `complete_document()` to `AIProvider` ABC and `GeminiProvider`, with a dedicated system prompt instructing the model to return the full rewritten document.
### v1.0.0 — Initial release
- Flask webhook server listening for Gitea push events.
- HMAC-SHA256 signature verification on all incoming webhooks.
- Scans changed `.md` files for `BLIGHT: <instruction>` trigger lines.
- Sends full document + instruction to Google Gemini 2.5 Flash-Lite.
- Replaces trigger line with AI response in-place and commits back to Gitea.
- Retry logic: 3 attempts with exponential backoff (1s, 2s, 4s).
- Processes webhooks in background threads to return 200 immediately.
- Deduplicates file paths across multiple commits in a single push.
- Self-updates on startup via `git pull --ff-only`.
- Pluggable `AIProvider` ABC for swapping AI backends.

View File

@@ -2,7 +2,7 @@
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.
BLIGHT: CUE monitors Gitea repositories containing markdown files. When a push is received, it scans changed files for `BLIGHT:` trigger lines, sends the document to an AI model along with the instruction, and writes the result back to the file in-place — fully automated.
---
@@ -10,16 +10,25 @@ BLIGHT: CUE monitors Gitea repositories containing markdown files. When a push i
1. You write a `BLIGHT:` trigger anywhere in a markdown file and push it to Gitea.
2. Gitea sends a webhook POST to this server.
3. The server fetches the file, finds all `BLIGHT:` triggers, and processes them one by one.
4. Each trigger is replaced with the AI's response at the exact position of the trigger line.
5. The updated file is committed back to the repo automatically.
3. The server fetches the file, finds all `BLIGHT:` triggers, and processes them.
4. Each trigger is replaced with the AI's response, then the updated file is committed back automatically.
### Trigger Syntax
Triggers are case-insensitive — `BLIGHT:`, `blight:`, `Blight::`, etc. all work.
**Inline trigger** — replaces only the trigger line with the AI's response:
```
BLIGHT: <your instruction here>
```
**Document-scope trigger** — replaces the entire file with the AI's rewritten version:
```
BLIGHT:: <your instruction here>
```
Examples:
```markdown
@@ -31,22 +40,30 @@ BLIGHT: Explain the key differences between は and が based on the paragraph a
```
```markdown
BLIGHT: Spell check this entire document and list any errors found.
BLIGHT: Write a conclusion paragraph for this document.
```
```markdown
BLIGHT: Write a conclusion paragraph for this document.
BLIGHT:: Spellcheck and lightly reformat this entire document.
```
### Processing Order
When a file contains multiple triggers:
1. All inline (`BLIGHT:`) triggers are processed first, in document order.
2. All document-scope (`BLIGHT::`) triggers are processed next, in document order — each one operates on the result of the previous.
### Failure Behavior
If the AI call fails after 3 attempts, the trigger is replaced with:
```html
<!-- BLIGHT_FAILED: your original instruction -->
<!-- BLIGHT_ERROR: <error message> -->
```
You can re-trigger processing by editing the file to restore the original `BLIGHT:` line and pushing again.
You can re-trigger processing by editing the file to restore the original trigger line and pushing again.
---
@@ -224,12 +241,17 @@ from abc import ABC, abstractmethod
class AIProvider(ABC):
def complete(self, document: str, instruction: str) -> str:
"""Return text to insert in place of an inline BLIGHT: trigger."""
...
def complete_document(self, document: str, instruction: str) -> str:
"""Return the full rewritten document for a BLIGHT:: trigger."""
...
```
To add a new provider (e.g. OpenRouter):
1. Create `ai/openrouter.py` and implement `AIProvider`.
1. Create `ai/openrouter.py` and implement both methods of `AIProvider`.
2. In `processor.py`, replace `GeminiProvider()` with your new class.
---