You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(github-pages): document swipe page and full manifest schema
- Document the per-digest swipe/triage page that is published alongside
each digest.
- Add an exhaustive manifest schema (top-level Manifest + every
ManifestEntry field).
- Replace the non-existent 'scheduler' section with how automatic
publishing actually works.
Copy file name to clipboardExpand all lines: docs/github-pages.md
+48-16Lines changed: 48 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@
3
3
Downlink can automatically publish each digest as a self-contained HTML page to a GitHub Pages repository. After every successful digest generation, it:
4
4
5
5
1. Clones (or pulls) your Pages repo locally.
6
-
2. Writes the digest HTML file (e.g. `digests/downlink-digest-2026-04-24_1200.html`).
6
+
2. Writes the digest HTML file (e.g. `digests/downlink-digest-2026-04-24_1200.html`) and a companion swipe/triage page (`digests/downlink-swipe-2026-04-24_1200.html`).
7
7
3. Regenerates `digests/index.html` and `digests/manifest.json` listing all digests, newest first.
8
8
4. Writes a root `index.html` that renders the digest archive and reads files from the configured output directory.
9
9
5. Commits and pushes the changed files.
@@ -15,13 +15,13 @@ Downlink can automatically publish each digest as a self-contained HTML page to
15
15
16
16
If you don't have one, create a repository named `<your-username>.github.io` (for a user site) or any repo with GitHub Pages enabled on a branch.
17
17
18
-
In the repo's **Settings → Pages**, set the source to the branch you'll push to (e.g. `main`, root `/`).
18
+
In the repo's **Settings -> Pages**, set the source to the branch you'll push to (e.g. `main`, root `/`).
19
19
20
20
---
21
21
22
22
## 2. Create a Personal Access Token
23
23
24
-
Go to **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens** (or classic tokens).
24
+
Go to **GitHub -> Settings -> Developer settings -> Personal access tokens -> Fine-grained tokens** (or classic tokens).
25
25
26
26
For normal publishing, the token needs **Contents: Read and write** on the target repository.
27
27
@@ -63,16 +63,16 @@ Add a `github_pages` block inside `notifications`:
63
63
| Field | Required | Default | Description |
64
64
|---|---|---|---|
65
65
|`enabled`| yes |`false`| Enable or disable publishing. |
66
-
|`repo_url`| yes |—| HTTPS clone URL of the Pages repo. |
66
+
|`repo_url`| yes |/| HTTPS clone URL of the Pages repo. |
67
67
|`branch`| no |`main`| Branch to clone and push to. When `configure_pages` is true, this is also configured as the GitHub Pages source branch. |
68
68
|`configure_pages`| no |`false`| Configure the GitHub Pages source to `branch` at `/` before publishing. Requires extra token permissions. |
69
-
|`token`| no*|—| GitHub PAT. Prefer `DOWNLINK_GH_PAGES_TOKEN` env var instead. |
69
+
|`token`| no*|/| GitHub PAT. Prefer `DOWNLINK_GH_PAGES_TOKEN` env var instead. |
70
70
|`output_dir`| no |`digests`| Safe relative subdirectory inside the repo where digest files are written. Absolute paths, `.`, `..`, and parent traversal are rejected. |
71
-
|`base_url`| no |—| Public URL of the site (e.g. `https://your-username.github.io`). Used to build links in Discord notifications. |
71
+
|`base_url`| no |/| Public URL of the site (e.g. `https://your-username.github.io`). Used to build links in Discord notifications. |
72
72
|`commit_author`| no |`downlink-bot`| Git commit author name. |
73
73
|`commit_email`| no |`downlink-bot@users.noreply.github.com`| Git commit author email. |
74
74
|`clone_dir`| no |`$TMPDIR/downlink-ghpages`| Local path where the repo is cloned. Persists across runs to avoid full re-clones. |
75
-
|`discord_webhook_url`| no |—| A **separate** Discord webhook to notify when a page is published. Distinct from the main digest webhook. |
75
+
|`discord_webhook_url`| no |/| A **separate** Discord webhook to notify when a page is published. Distinct from the main digest webhook. |
76
76
77
77
*\*`token` must be provided via config or environment variable for publishing to work.*
-**`<output_dir>/downlink-digest-YYYY-MM-DD_HHMM.html`** — self-contained dark-themed HTML page for that digest (same file sent to Discord).
130
-
-**`<output_dir>/manifest.json`** — machine-readable archive data for the digest index, newest first. Each digest entry includes `filename`, `started_at`, `time_window`, `article_count`, `must_count`, `should_count`, `may_count`, `opt_count`, `provider`, `model`, `headlines`, and `summary`.
131
-
-**`<output_dir>/index.html`** — regenerated archive UI with latest-digest hero, search, filters, sort controls, log/grid/timeline layouts, keyboard navigation, and pinned digests in browser local storage.
132
-
-**`index.html`** — root archive UI that loads `<output_dir>/manifest.json` and links digest pages under `<output_dir>`.
129
+
-**`<output_dir>/downlink-digest-YYYY-MM-DD_HHMM.html`** - self-contained dark-themed HTML page for that digest (same file sent to Discord).
130
+
-**`<output_dir>/downlink-swipe-YYYY-MM-DD_HHMM.html`** - self-contained mobile-friendly "swipe" triage view of the same digest, linked from the articles page. Shares its timestamp.
131
+
-**`<output_dir>/manifest.json`** - machine-readable archive data for the digest index, newest first. See [Manifest schema](#manifest-schema) below for every field.
132
+
-**`<output_dir>/index.html`** - regenerated archive UI with latest-digest hero, search, filters, sort controls, log/grid/timeline layouts, keyboard navigation, and pinned digests in browser local storage.
133
+
-**`index.html`** - root archive UI that loads `<output_dir>/manifest.json` and links digest pages under `<output_dir>`.
133
134
134
135
If `output_dir` is empty, Downlink uses `digests`. Publishing directly to the repo root is not supported.
135
136
136
137
The browser-facing archive index uses `manifest.json` directly. The manifest follows the current archive schema only; old manifests should be regenerated by publishing a new digest or reinitializing the Pages structure.
137
138
139
+
### Manifest schema
140
+
141
+
Top-level `manifest.json` object:
142
+
143
+
| Field | Type | Description |
144
+
|---|---|---|
145
+
|`generated_at`| string | Timestamp when the manifest was last (re)generated. |
146
+
|`source_repo`| string | The Pages repository URL the manifest was written to. |
147
+
|`digests`| array | List of digest entries, newest first (see below). |
148
+
149
+
Each entry in `digests`:
150
+
151
+
| Field | Type | Description |
152
+
|---|---|---|
153
+
|`filename`| string | Digest HTML filename (e.g. `downlink-digest-2026-04-24_1200.html`). |
154
+
|`started_at`| string | When digest generation started. |
155
+
|`period_start`| string | Start of the time window the digest covers. Omitted when unset. |
156
+
|`time_window`| string | Human-readable description of the covered time window. |
157
+
|`article_count`| int | Total number of articles in the digest. |
158
+
|`must_count`| int | Articles tagged "Must Read". |
159
+
|`should_count`| int | Articles tagged "Should Read". |
160
+
|`may_count`| int | Articles tagged "May Read". |
161
+
|`opt_count`| int | Articles tagged "Optional". |
162
+
|`provider`| string | Analysis provider used for the digest summary. |
163
+
|`model`| string | Primary model name. |
164
+
|`models`| array | All unique model names across the summary and per-article analysis. Omitted when empty. |
165
+
|`title`| string | Digest title. Omitted when unset. |
166
+
|`headlines`| array | Headline strings shown in the archive index. |
167
+
|`headline_priorities`| array | Per-headline priority labels, aligned with `headlines`. Omitted when empty. |
168
+
|`summary`| string | Digest summary (markdown). |
169
+
138
170
---
139
171
140
172
## 7. Discord publish notification
@@ -153,12 +185,12 @@ If `base_url` is not set, the message omits the URL. Failure to send this notifi
153
185
154
186
On the first publish, Downlink clones the repository into `clone_dir` (shallow, depth 1). On subsequent runs it pulls the latest from origin before writing and committing. This means:
155
187
156
-
- The clone persists between server restarts — no full re-clone each time.
188
+
- The clone persists between server restarts - no full re-clone each time.
157
189
- If two concurrent digest generations race, the second push may be rejected as non-fast-forward; Downlink will pull and retry once automatically.
158
190
- If you need to force a fresh clone, delete the `clone_dir` directory.
159
191
160
192
---
161
193
162
-
## 9. Scheduler usage
194
+
## 9. Automatic publishing
163
195
164
-
The scheduler triggers digest generation on the server via gRPC. Because publishing is wired into the server-side pipeline, no extra scheduler configuration is needed — any digest the scheduler generates will be published automatically if`github_pages.enabled` is `true` in the server's `config.json`.
196
+
Publishing is wired into the server-side digest pipeline, so no extra configuration is needed beyond `github_pages.enabled`. Any digest generated against the server - via `dlk digest generate` or the gRPC `DigestService` - is published automatically when`github_pages.enabled` is `true` in the server's `config.json`. To publish on a schedule, run `dlk digest generate` from cron (or any external scheduler) against the running server.
0 commit comments