Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.coolify.template
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ OPPER_API_KEY=your_opper_api_key_here
OPPER_MODEL=gpt-5.6-luna
OPPER_VARIANT=medium

# BLOC is qualified with OpenCode v1.19.3; OpenCode v2 is not yet qualified.
# Browse OpenCode image tags and digests at:
# https://github.com/anomalyco/opencode/pkgs/container/opencode
# Pin the digest for a version you have qualified; do not use a floating tag.
OPENCODE_IMAGE=ghcr.io/anomalyco/opencode@sha256:6ebc13097f2381301220abe9d1b2a54f50cd1603a910dc1c66e93d8f2c4e8ebb

# Optional GitHub CLI token passed only to the OpenCode service.
# Use a dedicated, least-privilege token; leave empty to disable GitHub authentication.
GH_TOKEN=
Expand Down
9 changes: 7 additions & 2 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ TELEGRAM_ENABLED=false
TELEGRAM_BOT_TOKEN=

# Required only when TELEGRAM_ENABLED=true. Comma-separated allowed chat IDs.
# Set this before startup; the bootstrap procedure for the first ID is still to be defined.
# To add another chat later, find its ID in the logs after its message is rejected.
# Discover the first ID safely with `make telegram-chat-id` before enabling Telegram.
TELEGRAM_ALLOWED_CHAT_IDS=

# Temporary, sanitized OpenCode cost/token diagnostics for an authorized test exchange.
Expand All @@ -24,3 +23,9 @@ OPPER_MODEL=gpt-5.6-luna

# Default OpenCode variant for this model.
OPPER_VARIANT=medium

# BLOC is qualified with OpenCode v1.19.3; OpenCode v2 is not yet qualified.
# Browse OpenCode image tags and digests for the main and repair Compose files at:
# https://github.com/anomalyco/opencode/pkgs/container/opencode
# Pin the digest for a version you have qualified; do not use a floating tag.
OPENCODE_IMAGE=ghcr.io/anomalyco/opencode@sha256:6ebc13097f2381301220abe9d1b2a54f50cd1603a910dc1c66e93d8f2c4e8ebb
19 changes: 18 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ permissions:
contents: read

jobs:
unit-tests:
checks:
runs-on: ubuntu-latest
steps:
- name: Check out repository
Expand All @@ -18,3 +18,20 @@ jobs:
python-version: "3.13"
- name: Run unit tests
run: make test
- name: Check Python syntax
run: python3 -m py_compile bot/telegram/*.py scripts/telegram_chat_id.py
- name: Validate Compose in both launch modes
run: |
env_file="$(mktemp)"
trap 'rm -f "$env_file"' EXIT
cat > "$env_file" <<'EOF'
TELEGRAM_ENABLED=false
TELEGRAM_BOT_TOKEN=ci-placeholder
TELEGRAM_ALLOWED_CHAT_IDS=123456789
OPPER_API_KEY=ci-placeholder
OPPER_MODEL=gpt-5.6-luna
OPPER_VARIANT=medium
OPENCODE_IMAGE=ghcr.io/anomalyco/opencode@sha256:6ebc13097f2381301220abe9d1b2a54f50cd1603a910dc1c66e93d8f2c4e8ebb
EOF
make config ENV_FILE="$env_file"
TELEGRAM_ENABLED=true make config ENV_FILE="$env_file"
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ __pycache__/
# secrets
.env
.env.coolify

backups/
# temporary files
tmp/
46 changes: 34 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
# Contributing

Run local operations through the root `Makefile`. Never commit `.env`, credentials,
OpenCode sessions, or Docker volume contents.
Use the root `Makefile` for project operations. Never commit `.env`, credentials, OpenCode
sessions, or Docker volume contents.

## Run tests
## Automated checks

Run the dependency-free unit tests with:

```sh
make test
```

The tests use Python's standard library and do not require credentials, Docker, or
access to Telegram or an LLM.
The tests use Python's standard library and need no credentials, Docker, Telegram, or LLM
access. Before submitting changes, also run:

```sh
make config
python3 -m py_compile bot/telegram/bridge.py
git diff --check
```

## Manual checks

For changes to configuration or deployment, validate the Compose configuration in the
intended mode. `make config` uses the local `.env`; check both OpenCode-only mode and
Telegram mode when applicable. Do not share the output of environment files or secrets.

For Telegram formatting changes, start the bridge and send the static fixture to an
already allowed chat:

```sh
make format-test CHAT_ID=<allowed-chat-id>
```

For an end-to-end check, start the services, send a message from an allowed chat, then
check `make status`, `make health`, and `make logs SERVICE=telegram`. The `/health` and
`/cost` commands check status and usage without making an LLM call.

## Draft a release

After the release changes are merged into `main`, checks have passed, and the version
has been approved, create and push an annotated tag, then create a GitHub draft:
After release changes are merged into `main`, checks have passed, and the version is
approved, create a GitHub draft with generated release notes. Replace the example version
with the approved tag:

```sh
git switch main
git pull --ff-only
VERSION='v0.X.Y' # replace with the approved version, e.g. v0.1.0
VERSION='v1.2.3' # replace if a different version is approved
git tag -a "$VERSION" -m "Release $VERSION"
git push origin "$VERSION"
gh release create "$VERSION" --draft --verify-tag --title "$VERSION" --generate-notes
```

`--verify-tag` requires the tag to have been pushed; `--draft` does not publish the
release. To provide hand-written notes, replace `--generate-notes` with
`--notes-file release-notes.md`. Review the draft before publishing. Never attach
`.env`, credentials, sessions, or Docker volumes.
`--verify-tag` requires the tag to have been pushed. Review the generated notes and draft
before publishing. Never attach `.env`, credentials, sessions, or Docker volumes.
15 changes: 13 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ SHELL := /bin/sh

ENV_FILE ?= .env
SERVICE ?=
BACKUP_DIR ?= backups
export ENV_FILE

COMPOSE_SCRIPT := ./scripts/compose.sh

.PHONY: help test diagnostics format-test check-env config build start stop down restart logs status health tui repair clean
.PHONY: help test diagnostics format-test telegram-chat-id backup restore check-env config build \
start stop down restart logs status health tui repair clean

help: ## Show available commands
@awk 'BEGIN {FS = ":.*## "} /^[a-zA-Z0-9_-]+:.*## / {printf "%-14s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@awk 'BEGIN {FS = ":.*## "} /^[a-zA-Z0-9_-]+:.*## / {printf "%-22s %s\n", $$1, $$2}' $(MAKEFILE_LIST)

test: ## Run dependency-free unit tests
@python3 -m unittest discover -s tests -v
Expand All @@ -20,6 +22,15 @@ diagnostics: ## Print sanitized Telegram cost diagnostics from the running bridg
format-test: ## Send a static Markdown formatting fixture; usage: make format-test CHAT_ID=<allowed-id>
@$(COMPOSE_SCRIPT) format-test "$(CHAT_ID)"

telegram-chat-id: ## Safely discover the first Telegram chat ID without starting the bridge
@ENV_FILE="$(ENV_FILE)" python3 scripts/telegram_chat_id.py

backup: ## Back up persistent volumes under backups/; override with BACKUP_DIR=<directory>
@$(COMPOSE_SCRIPT) backup "$(BACKUP_DIR)"

restore: ## Restore from the latest backup in backups/ or a specific BACKUP_DIR
@$(COMPOSE_SCRIPT) restore "$(BACKUP_DIR)"

check-env: ## Check that the environment file exists
@$(COMPOSE_SCRIPT) check-env

Expand Down
Loading
Loading