An open API service indexing awesome lists of open source software.

https://github.com/taciturnaxolotl/herald

rss email digests over ssh because you're a cool kid
https://github.com/taciturnaxolotl/herald

charm go rss rss-reader ssh

Last synced: 5 months ago
JSON representation

rss email digests over ssh because you're a cool kid

Awesome Lists containing this project

README

          

# Herald 🎏

![herald web interface](https://l4.dunkirk.sh/i/TuJ7meLh1JB9.webp)

This was inspired by the sunsetting of [pico.sh/feeds](https://blog.pico.sh/ann-033-moving-rss-to-email-pico-plus) being available outside of `pico+`. It is a totally understandable move from them as their email costs were skyrocketing and they needed to pay for it somehow. This was created to allow me to still get my rss feeds delivered to me each day by email which I have grown quite accustomed to. The config is completely compatible with the `pico.sh` format as of `2026-01-09` and should stay fairly stable. It is also configured over ssh with the slight addition that you can view your feeds on a website as well as I found myself wanting to hot load my feeds into my website :)

The canonical repo for this is hosted on tangled over at [`dunkirk.sh/herald`](https://tangled.org/@dunkirk.sh/herald)

## Quick Start

```bash
# Build
go build -ldflags "-X main.commitHash=$(git log -1 --format=%H)" -o herald .

# Run the server
./herald serve

# Or with a config file
./herald serve -c config.yaml
```

> **Note:** The commit hash is automatically detected at runtime if not embedded at build time.

## Usage

### Upload a config

Create a `feeds.txt` file:

```text
=: email you@example.com
=: cron 0 8 * * *
=: digest true
=> https://dunkirk.sh/atom.xml
=> https://news.ycombinator.com/rss
=> https://lobste.rs/rss "Lobsters"
```

Upload via SCP:

```bash
scp feeds.txt user@herald.dunkirk.sh:
```

### SSH Configuration

Add this to your `~/.ssh/config` for easier access:

```ssh-config
Host herald
HostName herald.dunkirk.sh
Port 2223
User herald
```

Then use: `scp feeds.txt herald:` and `ssh herald ls`

### SSH Commands

```bash
# Get your fingerprint (for web dashboard)
ssh herald.dunkirk.sh

# List your configs
ssh herald.dunkirk.sh ls

# Show config contents
ssh herald.dunkirk.sh cat feeds.txt

# Delete a config
ssh herald.dunkirk.sh rm feeds.txt

# Activate/deactivate configs
ssh herald.dunkirk.sh activate feeds.txt
ssh herald.dunkirk.sh deactivate feeds.txt

# Run immediately (don't wait for cron)
ssh herald.dunkirk.sh run feeds.txt

# Show recent activity
ssh herald.dunkirk.sh logs
```

### Web Interface

Visit `http://localhost:8080` for the landing page.

After uploading a config, run `ssh herald.dunkirk.sh` to get your fingerprint, then visit:

- `http://localhost:8080/{fingerprint}` - Your dashboard with config status
- `http://localhost:8080/{fingerprint}/feeds.xml` - RSS feed for feeds.txt
- `http://localhost:8080/{fingerprint}/feeds.json` - JSON feed for feeds.txt

## Config Format

### Directives

| Directive | Required | Description |
| ------------------- | -------- | ------------------------------------------------- |
| `=: email ` | Yes | Recipient email address |
| `=: cron ` | Yes | Standard cron expression (5 fields) |
| `=: digest ` | No | Combine all items into one email (default: true) |
| `=: inline ` | No | Include article content in email (default: false) |
| `=> ["name"]` | Yes (1+) | RSS/Atom feed URL, optional display name |

## Configuration

Create a `config.yaml`:

```yaml
host: 0.0.0.0
ssh_port: 2222
http_port: 8080

host_key_path: ./host_key
db_path: ./herald.db

smtp:
host: smtp.example.com
port: 587
user: sender@example.com
pass: ${SMTP_PASS}
from: herald@example.com

allow_all_keys: true
```

Environment variables can also be used:

- `HERALD_HOST`
- `HERALD_SSH_PORT`
- `HERALD_HTTP_PORT`
- `HERALD_DB_PATH`
- `HERALD_SMTP_HOST`
- `HERALD_SMTP_PORT`
- `HERALD_SMTP_USER`
- `HERALD_SMTP_PASS`
- `HERALD_SMTP_FROM`

## Screenshots

here is an example of what an email digest looks like:

![email from harold](https://l4.dunkirk.sh/i/Ck271POS5n0k.webp)




&copy 2025-present Kieran Klukas