docs: rewrite README to be less webhook centric

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I4a46610262c629f22bc61b8581a4a0336a6a6964
This commit is contained in:
raf 2026-02-01 15:36:28 +03:00
commit d952b973a8
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

231
README.md
View file

@ -3,10 +3,34 @@
Troutbot is the final solution to protecting the trout population. It's
environmental protection incarnate!
Well in reality, it's a GitHub webhook bot that analyzes issues and pull
requests using real signals such as CI check results, diff quality, and body
structure and then posts trout-themed comments about the findings. Now you know
whether your changes hurt or help the trout population.
Well, in reality, it is a GitHub bot that analyzes issues and pull requests
using real signals such as CI check results, diff quality, and body structure
and then posts trout-themed comments about the findings. Now you know whether
your changes hurt or help the trout population.
## Operation Modes
Troutbot supports two operation modes:
### Webhook Mode (Real-time)
GitHub sends webhook events to troutbot when issues/PRs are opened or updated.
Troutbot responds immediately. Best for:
- Single or few repositories
- You have admin access to configure webhooks
- You can expose a public endpoint
### Polling Mode (Periodic)
Troutbot periodically polls configured repositories for `@troutbot` mentions in
comments. Best for:
- Monitoring dozens of repositories without webhook setup
- Running behind a firewall or on dynamic IPs
- Simplified deployment without webhook secrets
Both modes use the same analysis engine and produce the same results.
## Quick Start
@ -17,18 +41,17 @@ $ npm install
# Populate the environment config
$ cp .env.example .env
# Set up application confg
# Set up application config
cp config.example.ts config.ts
# Edit .env and config.ts, then to start:
npm run build && npm start
# Edit .env and config.ts, then build and start.
# If `.env` is not populated, Troutbot will start in dry-run mode.
pnpm run build && pnpm start
```
## How It Works
Troutbot has three analysis backends ran against each incoming webhook event.
They are the primary decisionmaking logic behind whether your changes affect the
trout population negatively, or positively.
Troutbot has three analysis backends that analyze issues and PRs:
### `checks`
@ -71,6 +94,75 @@ checks 0.4, diff 0.3, quality 0.3). Backends that return zero confidence (e.g.,
no CI checks found yet) are excluded from the average. If combined confidence
falls below `confidenceThreshold`, the result is forced to neutral.
## Webhook Mode
In webhook mode, troutbot receives real-time events from GitHub.
### GitHub Webhook Setup
1. Go to your repository's **Settings > Webhooks > Add webhook**
2. **Payload URL**: `https://your-host/webhook`
3. **Content type**: `application/json`
4. **Secret**: Generate with `openssl rand -hex 32` and set as `WEBHOOK_SECRET`
5. **Events**: Select **Issues**, **Pull requests**, and optionally **Check
suites** (for re-analysis when CI finishes)
If you enable **Check suites** and set `response.allowUpdates: true` in your
config, troutbot will update its comment on a PR once CI results are available.
### Webhook Security
- **`WEBHOOK_SECRET` is strongly recommended.** Without it, anyone who can reach
the `/webhook` endpoint can trigger analysis and post comments. Always set a
secret and configure the same value in your GitHub webhook settings.
## Polling Mode
In polling mode, troutbot periodically checks configured repositories for
`@troutbot` mentions in comments.
### Configuration
Enable polling in your `config.ts`:
```typescript
polling: {
enabled: true,
intervalMinutes: 5, // Check every 5 minutes
lookbackMinutes: 10, // Look back 10 minutes for new comments
}
```
### How It Works
1. On startup, troutbot fetches recent comments from all configured repositories
2. It scans each comment for `@troutbot` mentions
3. When found, it analyzes the associated issue/PR and posts a response
4. Processed comments are tracked to avoid duplicate responses
5. The cycle repeats every `intervalMinutes`
### On-Demand Analysis
Users can trigger analysis by mentioning `@troutbot` in any comment:
```plaintext
Hey @troutbot, can you take a look at this?
```
The bot will analyze the issue/PR and respond with a trout-themed assessment.
### Rate Limiting
Polling uses the GitHub REST API and respects rate limits. The default settings
(5 min interval, 10 min lookback) are conservative and work well within GitHub's
5000 requests/hour limit for personal access tokens.
### Requirements
- `GITHUB_TOKEN` with read access to all watched repositories
- Repositories configured in `config.repositories`
- Write access to post comments
## GitHub Account & Token Setup
Troutbot is designed to run as a dedicated bot account on GitHub. Create a
@ -89,8 +181,7 @@ The bot account needs access to every repository it will comment on:
- **For organization repos**: Invite the bot account as a collaborator with
**Write** access, or add it to a team with write permissions.
- **For personal repos**: Add the bot account as a collaborator under
\*\*Settings
> Collaborators\*\*.
`Settings > Collaborators`.
The bot needs write access to post comments. Read access alone is not enough.
@ -98,10 +189,10 @@ The bot needs write access to post comments. Read access alone is not enough.
Log in as the bot account and create a fine-grained PAT:
1. Go to **Settings > Developer settings > Personal access tokens > Fine-grained
tokens**
1. Go to
`Settings > Developer settings > Personal access tokens > Fine-grained tokens`
2. Click **Generate new token**
3. Set a descriptive name (e.g., `troutbot-webhook`)
3. Set a descriptive name (e.g., `troutbot-production`)
4. Set **Expiration** - pick a long-lived duration or no expiration, since this
runs unattended
5. Under **Repository access**, select the specific repositories the bot will
@ -121,19 +212,7 @@ Set this as the `GITHUB_TOKEN` environment variable.
> `repo` scope. Fine-grained tokens are recommended because they follow the
> principle of least privilege.
### 4. Generate a webhook secret
Generate a random secret to verify webhook payloads:
```bash
openssl rand -hex 32
```
Set this as the `WEBHOOK_SECRET` environment variable, and use the same value
when configuring the webhook in GitHub (see
[GitHub Webhook Setup](#github-webhook-setup)).
## Configuration
## Configuring Troutbot
### Environment Variables
@ -142,7 +221,7 @@ when configuring the webhook in GitHub (see
| Variable | Description | Required |
| ---------------- | ----------------------------------------------------- | ---------------------------- |
| `GITHUB_TOKEN` | Fine-grained PAT from the bot account (see above) | No (dry-run without it) |
| `WEBHOOK_SECRET` | Secret for verifying webhook signatures | No (skips verification) |
| `WEBHOOK_SECRET` | Secret for verifying webhook signatures | No (only for webhook mode) |
| `PORT` | Server port (overrides `server.port` in config) | No |
| `CONFIG_PATH` | Path to config file | No (defaults to `config.ts`) |
| `LOG_LEVEL` | Log level override (`debug`, `info`, `warn`, `error`) | No |
@ -156,10 +235,11 @@ default-exports a `Config` object - full type checking and autocompletion in
your editor.
```typescript
import type { Config } from "./src/types";
import type { Config } from './src/types';
const config: Config = {
server: { port: 3000 },
repositories: [{ owner: 'myorg', repo: 'myrepo' }],
engine: {
backends: {
checks: { enabled: true },
@ -169,6 +249,11 @@ const config: Config = {
weights: { checks: 0.4, diff: 0.3, quality: 0.3 },
confidenceThreshold: 0.1,
},
polling: {
enabled: true,
intervalMinutes: 5,
lookbackMinutes: 10,
},
// ...
};
@ -180,28 +265,13 @@ pre-compilation needed.
See `config.example.ts` for the full annotated reference.
## GitHub Webhook Setup
1. Go to your repository's **Settings > Webhooks > Add webhook**
2. **Payload URL**: `https://your-host/webhook`
3. **Content type**: `application/json`
4. **Secret**: Must match your `WEBHOOK_SECRET` env var
5. **Events**: Select **Issues**, **Pull requests**, and optionally **Check
suites** (for re-analysis when CI finishes)
If you enable **Check suites** and set `response.allowUpdates: true` in your
config, troutbot will update its comment on a PR once CI results are available.
## Production Configuration
When deploying troutbot to production, keep the following in mind:
- **`WEBHOOK_SECRET` is strongly recommended.** Without it, anyone who can reach
the `/webhook` endpoint can trigger analysis and post comments. Always set a
secret and configure the same value in your GitHub webhook settings.
- **Use a reverse proxy with TLS.** GitHub sends webhook payloads over HTTPS.
Put nginx, Caddy, or a cloud load balancer in front of troutbot and terminate
TLS there.
- **Use a reverse proxy with TLS.** If using webhook mode, GitHub sends payloads
over HTTPS. Put nginx, Caddy, or a cloud load balancer in front of troutbot
and terminate TLS there. Polling mode doesn't require a public endpoint.
- **Set `NODE_ENV=production`.** This is set automatically in the Docker image.
For standalone deployments, export it in your environment. Express uses this
to enable performance optimizations.
@ -218,22 +288,19 @@ When deploying troutbot to production, keep the following in mind:
## Deployment
<details>
<summary>Standalone (Node.js)</summary>
### Standalone (Node.js)
```bash
npm ci
npm run build
export NODE_ENV=production
export GITHUB_TOKEN="ghp_..."
export WEBHOOK_SECRET="your-secret"
# Only needed for webhook mode:
# export WEBHOOK_SECRET="your-secret"
npm start
```
</details>
<details>
<summary>Nix</summary>
### Nix
**Flake** (NixOS or flake-enabled systems):
@ -248,8 +315,8 @@ npm start
{
services.troutbot = {
enable = true;
environmentFile = "/path/to/.env"; # use Agenix if possible
configPath = "/path/to/config.ts" # use Agenix if possible
environmentFile = "/path/to/.env";
configPath = "/path/to/config.ts";
};
}
];
@ -264,10 +331,7 @@ npm start
nix run github:notashelf/troutbot
```
</details>
<details>
<summary>Docker</summary>
### Docker
```bash
docker build -t troutbot .
@ -275,7 +339,6 @@ docker run -d \
--name troutbot \
-p 127.0.0.1:3000:3000 \
-e GITHUB_TOKEN="ghp_..." \
-e WEBHOOK_SECRET="your-secret" \
-v $(pwd)/config.ts:/app/config.ts:ro \
--restart unless-stopped \
troutbot
@ -283,17 +346,14 @@ docker run -d \
Multi-stage build, non-root user, built-in health check, `STOPSIGNAL SIGTERM`.
</details>
<details>
<summary>Docker Compose</summary>
### Docker Compose
```yaml
services:
troutbot:
build: .
ports:
- "127.0.0.1:3000:3000"
- '127.0.0.1:3000:3000'
env_file: .env
volumes:
- ./config.ts:/app/config.ts:ro
@ -305,20 +365,17 @@ services:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
max-size: '10m'
max-file: '3'
```
</details>
<details>
<summary>systemd</summary>
### Systemd
Create `/etc/systemd/system/troutbot.service`:
```ini
[Unit]
Description=Troutbot GitHub Webhook Bot
Description=Troutbot GitHub Bot
After=network.target
[Service]
@ -345,10 +402,9 @@ sudo systemctl daemon-reload
sudo systemctl enable --now troutbot
```
</details>
### Reverse Proxy (nginx)
<details>
<summary>Reverse Proxy (nginx)</summary>
Only needed for webhook mode:
```nginx
server {
@ -369,7 +425,7 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}
# Optional: nginx-level rate limiting
# Optional: nginx-level rate limiting for webhooks
# limit_req_zone $binary_remote_addr zone=webhook:10m rate=10r/s;
# location /webhook {
# limit_req zone=webhook burst=20 nodelay;
@ -378,21 +434,23 @@ server {
}
```
</details>
## API Endpoints
<!--markdownlint-disable MD013-->
| Method | Path | Description |
| -------- | ------------- | ---------------------------------------------------------------------------------------- |
| `GET` | `/health` | Health check - returns `status`, `uptime` (seconds), `version`, `dryRun`, and `backends` |
| `POST` | `/webhook` | GitHub webhook receiver (rate limited) |
| `POST` | `/webhook` | GitHub webhook receiver (rate limited, webhook mode only) |
| `GET` | `/dashboard` | Web UI dashboard with status, events, and config editor |
| `GET` | `/api/status` | JSON status: uptime, version, dry-run, backends, repo count |
| `GET` | `/api/events` | Recent webhook events from the in-memory ring buffer |
| `GET` | `/api/events` | Recent events from the in-memory ring buffer |
| `DELETE` | `/api/events` | Clear the event ring buffer |
| `GET` | `/api/config` | Current runtime configuration as JSON |
| `PUT` | `/api/config` | Partial config update: deep-merges, validates, and applies in-place |
<!--markdownlint-enable MD013-->
## Dashboard & Runtime API
Troutbot ships with a built-in web dashboard and JSON API for monitoring and
@ -405,9 +463,8 @@ running). The dashboard provides:
- **Status card** - uptime, version, dry-run state, active backends, and repo
count. Auto-refreshes every 30 seconds.
- **Event log** - table of recent webhook events showing repo, PR/issue number,
action, impact rating, and confidence score. Keeps the last 100 events in
memory.
- **Event log** - table of recent events showing repo, PR/issue number, action,
impact rating, and confidence score. Keeps the last 100 events in memory.
- **Config editor** - read-only JSON view of the current runtime config with an
"Edit" toggle that lets you modify and save changes without restarting.
@ -441,8 +498,8 @@ original config remains unchanged if validation fails.
### Event Buffer API
The event buffer stores the last 100 processed webhook events in memory. Events
are lost on restart.
The event buffer stores the last 100 processed events in memory (from both
webhooks and polling). Events are lost on restart.
```bash
# List recent events